File Coverage

blib/lib/Image/ExifTool/Samsung.pm
Criterion Covered Total %
statement 103 207 49.7
branch 39 112 34.8
condition 25 73 34.2
subroutine 7 11 63.6
pod 0 6 0.0
total 174 409 42.5


line stmt bran cond sub pod time code
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) Nick Livchits private communication
13             # 6) Sreerag Raghavan private communication (SM-C200)
14             # IB) Iliah Borg private communication (LibRaw)
15             # NJ) Niels Kristian Bech Jensen private communication
16             #------------------------------------------------------------------------------
17              
18             package Image::ExifTool::Samsung;
19              
20 15     15   118 use strict;
  15         37  
  15         790  
21 15     15   99 use vars qw($VERSION %samsungLensTypes);
  15         28  
  15         1143  
22 15     15   97 use Image::ExifTool qw(:DataAccess :Utils);
  15         50  
  15         4459  
23 15     15   125 use Image::ExifTool::Exif;
  15         32  
  15         446  
24 15     15   9701 use Image::ExifTool::JSON;
  15         88  
  15         92290  
25              
26             $VERSION = '1.62';
27              
28             sub WriteSTMN($$$);
29             sub ProcessINFO($$$);
30             sub ProcessSamsungMeta($$$);
31             sub ProcessSamsungIFD($$$);
32             sub ProcessSamsung($$;$);
33              
34             # Samsung LensType lookup
35             %samsungLensTypes = (
36             # (added "Samsung NX" in all of these lens names - ref 4)
37             0 => 'Built-in or Manual Lens', #PH (EX1, WB2000)
38             1 => 'Samsung NX 30mm F2 Pancake',
39             2 => 'Samsung NX 18-55mm F3.5-5.6 OIS', # (also version II, ref 1)
40             3 => 'Samsung NX 50-200mm F4-5.6 ED OIS',
41             # what about the non-OIS version of the 18-55,
42             # which was supposed to be available before the 20-50? - PH
43             4 => 'Samsung NX 20-50mm F3.5-5.6 ED', #PH/4
44             5 => 'Samsung NX 20mm F2.8 Pancake', #PH
45             6 => 'Samsung NX 18-200mm F3.5-6.3 ED OIS', #4
46             7 => 'Samsung NX 60mm F2.8 Macro ED OIS SSA', #1
47             8 => 'Samsung NX 16mm F2.4 Pancake', #1/4
48             9 => 'Samsung NX 85mm F1.4 ED SSA', #4
49             10 => 'Samsung NX 45mm F1.8', #3
50             11 => 'Samsung NX 45mm F1.8 2D/3D', #3
51             12 => 'Samsung NX 12-24mm F4-5.6 ED', #4
52             13 => 'Samsung NX 16-50mm F2-2.8 S ED OIS', #forum3833
53             14 => 'Samsung NX 10mm F3.5 Fisheye', #NJ
54             15 => 'Samsung NX 16-50mm F3.5-5.6 Power Zoom ED OIS', #5
55             20 => 'Samsung NX 50-150mm F2.8 S ED OIS', #PH
56             21 => 'Samsung NX 300mm F2.8 ED OIS', #IB
57             );
58              
59             # range of values for Formats used in encrypted information
60             my %formatMinMax = (
61             int16u => [ 0, 65535 ],
62             int32u => [ 0, 4294967295 ],
63             int16s => [ -32768, 32767 ],
64             int32s => [ -2147483648, 2147483647 ],
65             );
66              
67             # Samsung "STMN" maker notes (ref PH)
68             %Image::ExifTool::Samsung::Main = (
69             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
70             WRITE_PROC => \&WriteSTMN,
71             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
72             WRITABLE => 1,
73             FORMAT => 'int32u',
74             FIRST_ENTRY => 0,
75             IS_OFFSET => [ 2 ], # tag 2 is 'IsOffset'
76             IS_SUBDIR => [ 11 ],
77             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
78             NOTES => q{
79             Tags found in the binary "STMN" format maker notes written by a number of
80             Samsung models.
81             },
82             0 => {
83             Name => 'MakerNoteVersion',
84             Format => 'undef[8]',
85             },
86             2 => {
87             Name => 'PreviewImageStart',
88             OffsetPair => 3, # associated byte count tagID
89             DataTag => 'PreviewImage',
90             IsOffset => 3,
91             Protected => 2,
92             WriteGroup => 'MakerNotes',
93             },
94             3 => {
95             Name => 'PreviewImageLength',
96             OffsetPair => 2, # point to associated offset
97             DataTag => 'PreviewImage',
98             Protected => 2,
99             WriteGroup => 'MakerNotes',
100             },
101             11 => {
102             Name => 'SamsungIFD',
103             # Note: this is not always an IFD. In many models the string
104             # "Park Byeongchan" is found at this location
105             Condition => '$$valPt =~ /^[^\0]\0\0\0/',
106             Format => 'undef[$size - 44]',
107             SubDirectory => { TagTable => 'Image::ExifTool::Samsung::IFD' },
108             },
109             );
110              
111             %Image::ExifTool::Samsung::IFD = (
112             PROCESS_PROC => \&ProcessSamsungIFD,
113             NOTES => q{
114             This is a standard-format IFD found in the maker notes of some Samsung
115             models, except that the entry count is a 4-byte integer and the offsets are
116             relative to the end of the IFD. Currently, no tags in this IFD are known,
117             so the L (-u) or L (-v) option must be used to see this
118             information.
119             },
120             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
121             # 0x0001 - undef[4000|4100]: starts with "MN_PRV" (or all zeros)
122             # 0x0002 - undef[7000] : starts with "Kim Miae"
123             # 0x0003 - undef[5000] : starts with "Lee BK"
124             # 0x0004 - undef[500|2000] : starts with "IPCD" (or all zeros)
125             # 0x0006 - undef[100|200] : starts with "MN_ADS" (or all zeros)
126             );
127              
128             # Samsung maker notes (ref PH)
129             %Image::ExifTool::Samsung::Type2 = (
130             WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
131             CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
132             WRITABLE => 1,
133             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
134             NOTES => 'Tags found in the EXIF-format maker notes of newer Samsung models.',
135             0x0001 => {
136             Name => 'MakerNoteVersion',
137             Writable => 'undef',
138             Count => 4,
139             },
140             0x0002 => {
141             Name => 'DeviceType',
142             Groups => { 2 => 'Camera' },
143             Writable => 'int32u',
144             PrintHex => 1,
145             PrintConv => {
146             0x1000 => 'Compact Digital Camera',
147             0x2000 => 'High-end NX Camera',
148             0x3000 => 'HXM Video Camera',
149             0x12000 => 'Cell Phone',
150             0x300000 => 'SMX Video Camera',
151             },
152             },
153             0x0003 => {
154             Name => 'SamsungModelID',
155             Groups => { 2 => 'Camera' },
156             Writable => 'int32u',
157             PrintHex => 1,
158             PrintConv => {
159             0x100101c => 'NX10',
160             0x1001226 => 'HMX-S10BP',
161             0x1001226 => 'HMX-S15BP',
162             0x1001233 => 'HMX-Q10',
163             0x1001234 => 'HMX-H300',
164             0x1001234 => 'HMX-H304',
165             0x100130c => 'NX100',
166             0x1001327 => 'NX11',
167             0x170104b => 'ES65, ES67 / VLUU ES65, ES67 / SL50',
168             0x170104e => 'ES70, ES71 / VLUU ES70, ES71 / SL600',
169             0x1701052 => 'ES73 / VLUU ES73 / SL605',
170             0x1701055 => 'ES25, ES27 / VLUU ES25, ES27 / SL45',
171             0x1701300 => 'ES28 / VLUU ES28',
172             0x1701303 => 'ES74,ES75,ES78 / VLUU ES75,ES78',
173             0x2001046 => 'PL150 / VLUU PL150 / TL210 / PL151',
174             0x2001048 => 'PL100 / TL205 / VLUU PL100 / PL101',
175             0x2001311 => 'PL120,PL121 / VLUU PL120,PL121',
176             0x2001315 => 'PL170,PL171 / VLUUPL170,PL171',
177             0x200131e => 'PL210, PL211 / VLUU PL210, PL211',
178             0x2701317 => 'PL20,PL21 / VLUU PL20,PL21',
179             0x2a0001b => 'WP10 / VLUU WP10 / AQ100',
180             0x3000000 => 'Various Models (0x3000000)',
181             #0x3000000 => 'DV150F / DV151F / DV155F',
182             #0x3000000 => 'NX mini',
183             #0x3000000 => 'NX3000',
184             #0x3000000 => 'NX3300',
185             #0x3000000 => 'ST150F / ST151F / ST152F',
186             #0x3000000 => 'WB200F / WB201F / WB202F',
187             #0x3000000 => 'WB250F / WB251F / WB252F',
188             #0x3000000 => 'WB30F / WB31F / WB32F',
189             #0x3000000 => 'WB350F / WB351F / WB352F',
190             #0x3000000 => 'WB800F',
191             0x3a00018 => 'Various Models (0x3a00018)',
192             #0x3a00018 => 'ES30 / VLUU ES30',
193             #0x3a00018 => 'ES80 / ES81',
194             #0x3a00018 => 'ES9 / ES8',
195             #0x3a00018 => 'PL200 / VLUU PL200',
196             #0x3a00018 => 'PL80 / VLUU PL80 / SL630 / PL81',
197             #0x3a00018 => 'PL90 / VLUU PL90',
198             #0x3a00018 => 'WB1100F / WB1101F / WB1102F',
199             #0x3a00018 => 'WB2200F',
200             0x400101f => 'ST1000 / ST1100 / VLUU ST1000 / CL65',
201             0x4001022 => 'ST550 / VLUU ST550 / TL225',
202             0x4001025 => 'Various Models (0x4001025)',
203             #0x4001025 => 'DV300 / DV300F / DV305F',
204             #0x4001025 => 'ST500 / VLUU ST500 / TL220',
205             #0x4001025 => 'ST200 / ST200F / ST201 / ST201F / ST205F',
206             0x400103e => 'VLUU ST5500, ST5500, CL80',
207             0x4001041 => 'VLUU ST5000, ST5000, TL240',
208             0x4001043 => 'ST70 / VLUU ST70 / ST71',
209             0x400130a => 'Various Models (0x400130a)',
210             #0x400130a => 'VLUU ST100, ST100',
211             #0x400130a => 'VLUU ST600, ST600',
212             #0x400130a => 'VLUU ST80, ST80',
213             0x400130e => 'ST90,ST91 / VLUU ST90,ST91',
214             0x4001313 => 'VLUU ST95, ST95',
215             0x4a00015 => 'VLUU ST60',
216             0x4a0135b => 'ST30, ST65 / VLUU ST65 / ST67',
217             0x5000000 => 'Various Models (0x5000000)',
218             #0x5000000 => 'EX2F',
219             #0x5000000 => 'NX1000',
220             #0x5000000 => 'NX20',
221             #0x5000000 => 'NX200',
222             #0x5000000 => 'NX210',
223             #0x5000000 => 'ST96',
224             #0x5000000 => 'WB750',
225             #0x5000000 => 'ST700',
226             0x5001038 => 'Various Models (0x5001038)',
227             #0x5001038 => 'EK-GN120',
228             #0x5001038 => 'HMX-E10',
229             #0x5001038 => 'NX1',
230             #0x5001038 => 'NX2000',
231             #0x5001038 => 'NX30',
232             #0x5001038 => 'NX300',
233             #0x5001038 => 'NX500',
234             #0x5001038 => 'SM-C200',
235             #0x5001038 => 'WB2000',
236             0x500103a => 'WB650 / VLUU WB650 / WB660',
237             0x500103c => 'WB600 / VLUU WB600 / WB610',
238             0x500133e => 'WB150 / WB150F / WB152 / WB152F / WB151',
239             0x5a0000f => 'WB5000 / HZ25W',
240             0x5a0001e => 'WB5500 / VLUU WB5500 / HZ50W',
241             0x6001036 => 'EX1',
242             0x700131c => 'VLUU SH100, SH100',
243             0x27127002 => 'SMX-C20N',
244             },
245             },
246             # 0x0004 - undef[x] (SamsungContentsID?)
247             # 0x000a - int32u (ContinuousShotMode?)
248             # 0x000b - int16u (BestPhotoMode?)
249             # 0x000c - int32u ? values: 0,1
250             # 0x000e - int32u[2] (SoundMultiPicture?)
251             # 0x0010 - rational64u ? values: undef,inf
252             0x0011 => { #6
253             Name => 'OrientationInfo',
254             SubDirectory => { TagTable => 'Image::ExifTool::Samsung::OrientationInfo' },
255             },
256             0x0020 => [{ #forum7685
257             Name => 'SmartAlbumColor',
258             Condition => '$$valPt =~ /^\0{4}/',
259             Writable => 'int16u',
260             Count => 2,
261             PrintConv => {
262             '0 0' => 'n/a',
263             },
264             },{
265             Name => 'SmartAlbumColor',
266             Writable => 'int16u',
267             Count => 2,
268             PrintConv => [{
269             0 => 'Red',
270             1 => 'Yellow',
271             2 => 'Green',
272             3 => 'Blue',
273             4 => 'Magenta',
274             5 => 'Black',
275             6 => 'White',
276             7 => 'Various',
277             }],
278             }],
279             0x0021 => { #1
280             Name => 'PictureWizard',
281             Writable => 'int16u',
282             SubDirectory => { TagTable => 'Image::ExifTool::Samsung::PictureWizard' },
283             },
284             # 0x0022 - int32u (CaptureMode?) (Gamma? eg. 65538 = 1.2, ref forum7720)
285             # 0x0023 - string: "0123456789" (PH) (placeholder for SerialNumber?)
286             # 0x0025 - int32u (ImageCount?)
287             # 0x002a - undef[4] (SNSDirectShare?)
288             # 0x002f - string (GPSInfo01?)
289             0x0030 => { #1 (NX100 with GPS)
290             Name => 'LocalLocationName',
291             Groups => { 2 => 'Location' },
292             Writable => 'string',
293             Format => 'undef',
294             # this contains 2 place names (in Korean if in Korea), separated by a null+space
295             # - terminate at double-null and replace nulls with newlines
296             ValueConv => '$val=~s/\0\0.*//; $val=~s/\0 */\n/g; $val',
297             ValueConvInv => '$val=~s/(\x0d\x0a|\x0d|\x0a)/\0 /g; $val . "\0\0"'
298             },
299             0x0031 => { #1 (NX100 with GPS)
300             Name => 'LocationName',
301             Groups => { 2 => 'Location' },
302             Writable => 'string',
303             },
304             # 0x0032 - string (GPSInfo03)
305             # 0x0033 - string (GPSInfo04)
306             # 0x0034 - string (GPSInfo05)
307             0x0035 => [{
308             Name => 'PreviewIFD',
309             Condition => '$$self{TIFF_TYPE} eq "SRW" and $$self{Model} ne "EK-GN120"', # (not an IFD in JPEG images)
310             Groups => { 1 => 'PreviewIFD' },
311             Flags => 'SubIFD',
312             SubDirectory => {
313             TagTable => 'Image::ExifTool::Nikon::PreviewIFD',
314             ByteOrder => 'Unknown',
315             Start => '$val',
316             },
317             },{
318             Name => 'PreviewIFD',
319             Condition => '$$self{TIFF_TYPE} eq "SRW"', # (not an IFD in JPEG images)
320             Groups => { 1 => 'PreviewIFD' },
321             Flags => 'SubIFD',
322             SubDirectory => {
323             TagTable => 'Image::ExifTool::Nikon::PreviewIFD',
324             ByteOrder => 'Unknown',
325             Start => '$val - 36',
326             },
327             }],
328             # 0x003a - int16u[2] (SmartLensInfo?)
329             # 0x003b - int16u[2] (PhotoStyleSelectInfo?)
330             # 0x003c - int16u (SmartRange?)
331             # 0x003d - int16u[5] (SmartCropInfo?)
332             # 0x003e - int32u (DualCapture?)
333             # 0x003f - int16u[2] (SGIFInfo?)
334             0x0040 => { #forum7432
335             Name => 'RawDataByteOrder',
336             PrintConv => {
337             0 => 'Little-endian (Intel, II)',
338             1 => 'Big-endian (Motorola, MM)', #(NC)
339             },
340             },
341             0x0041 => { #forum7684
342             Name => 'WhiteBalanceSetup',
343             Writable => 'int32u',
344             PrintConv => {
345             0 => 'Auto',
346             1 => 'Manual',
347             },
348             },
349             0x0043 => { #1 (NC)
350             Name => 'CameraTemperature',
351             Groups => { 2 => 'Camera' },
352             Writable => 'rational64s',
353             # (DPreview samples all 0.2 C --> pre-production model)
354             PrintConv => '$val =~ /\d/ ? "$val C" : $val',
355             PrintConvInv => '$val=~s/ ?C//; $val',
356             },
357             # 0x0045 => { Name => 'RawCompressionMode', Writable => 'int32u' }, # (related to ExposureMode, not raw compresison? ref forum7432)
358             # 0x004a - int32u[7] (ImageVerification?)
359             # 0x004b - int32u[2] (RewindInfo?)
360             # 0x0050 - int32u (ColorSpace? - inconsistent) values: 1 (related to compression mode, ref forum7432)
361             0x0050 => { #forum7432
362             Name => 'RawDataCFAPattern',
363             PrintConv => {
364             0 => 'Unchanged',
365             1 => 'Swap',
366             65535 => 'Roll',
367             },
368             },
369             # 0x0054 - int16u[2] (WeatherInfo?)
370             # 0x0060 - undef (AEInfo?)
371             # 0x0080 - undef (AFInfo?)
372             # 0x00a0 - undef[8192] (AWBInfo1): white balance information (ref 1):
373             # At byte 5788, the WBAdjust: "Adjust\0\X\0\Y\0\Z\xee\xea\xce\xab", where
374             # Y = BA adjust (0=Blue7, 7=0, 14=Amber7), Z = MG (0=Magenta7, 7=0, 14=Green7)
375             # 0x00a1 - undef (AWBInfo2?)
376             # 0x00c0 - undef (IPCInfo?)
377             # 0x00c7 - undef (SmartFunctionInfo?)
378             # 0x00e0 - int16u (SceneResult?)
379             # 0x00e1 - int16u[8] (SADebugInfo01?)
380             # 0x00e1 - int16u[x] (SADebugInfo02?)
381             0x0100 => {
382             Name => 'FaceDetect',
383             Writable => 'int16u',
384             PrintConv => { 0 => 'Off', 1 => 'On' }, #(NC)
385             },
386             # 0x0101 - int16u[6] (FaceDetectInfo?)
387             # 0x0102 - int16u[x] (FaceDetectInfo?)
388             0x0120 => {
389             Name => 'FaceRecognition',
390             Writable => 'int32u',
391             PrintConv => { 0 => 'Off', 1 => 'On' }, #(NC)
392             },
393             0x0123 => { Name => 'FaceName', Writable => 'string' },
394             # 0x140 - undef (LensInfo?)
395             #
396             # the following tags found only in SRW images
397             #
398             # 0xa000 - rational64u: 1 or 1.1 (ref PH) (MakerNoteVersion?)
399             0xa001 => { #1
400             Name => 'FirmwareName',
401             Groups => { 2 => 'Camera' },
402             Writable => 'string',
403             },
404             0xa002 => { #PH/IB
405             Name => 'SerialNumber',
406             Condition => '$$valPt =~ /^\w{5}/', # should be at least 5 characters long
407             Groups => { 2 => 'Camera' },
408             Writable => 'string',
409             },
410             0xa003 => { #1 (SRW images only)
411             Name => 'LensType',
412             Groups => { 2 => 'Camera' },
413             Writable => 'int16u',
414             Count => -1,
415             PrintConv => [ \%samsungLensTypes ],
416             },
417             0xa004 => { #1
418             Name => 'LensFirmware',
419             Groups => { 2 => 'Camera' },
420             Writable => 'string',
421             },
422             0xa005 => {
423             Name => 'InternalLensSerialNumber', # Not the printed serial number (ref 1)
424             Groups => { 2 => 'Camera' },
425             Writable => 'string',
426             },
427             0xa010 => { #1
428             Name => 'SensorAreas',
429             Groups => { 2 => 'Camera' },
430             Notes => 'full and valid sensor areas',
431             Writable => 'int32u',
432             Count => 8,
433             },
434             0xa011 => { #1
435             Name => 'ColorSpace',
436             Writable => 'int16u',
437             PrintConv => {
438             0 => 'sRGB',
439             1 => 'Adobe RGB',
440             },
441             },
442             0xa012 => { #1
443             Name => 'SmartRange',
444             Writable => 'int16u',
445             PrintConv => { 0 => 'Off', 1 => 'On' },
446             },
447             0xa013 => { #1
448             Name => 'ExposureCompensation',
449             Writable => 'rational64s',
450             },
451             0xa014 => { #1
452             Name => 'ISO',
453             Writable => 'int32u',
454             },
455             0xa018 => { #1
456             Name => 'ExposureTime',
457             Writable => 'rational64u',
458             ValueConv => '$val=~s/ .*//; $val', # some models write 2 values here
459             ValueConvInv => '$val',
460             PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
461             PrintConvInv => '$val',
462             },
463             0xa019 => { #1
464             Name => 'FNumber',
465             Priority => 0,
466             Writable => 'rational64u',
467             ValueConv => '$val=~s/ .*//; $val', # some models write 2 values here
468             ValueConvInv => '$val',
469             PrintConv => 'sprintf("%.1f",$val)',
470             PrintConvInv => '$val',
471             },
472             0xa01a => { #1
473             Name => 'FocalLengthIn35mmFormat',
474             Groups => { 2 => 'Camera' },
475             Priority => 0,
476             Format => 'int32u',
477             ValueConv => '$val / 10',
478             ValueConvInv => '$val * 10',
479             PrintConv => '"$val mm"',
480             PrintConvInv => '$val=~s/\s*mm$//;$val',
481             },
482             # 0xa01b - int32u (ImageCount?)
483             # 0xa01b - int16u (LDCLens?)
484             0xa020 => { #1
485             Name => 'EncryptionKey',
486             Writable => 'int32u',
487             Count => 11,
488             Protected => 1,
489             DataMember => 'EncryptionKey',
490             RawConv => '$$self{EncryptionKey} = [ split(" ",$val) ]; $val',
491             Notes => 'key used to decrypt the tags below',
492             # value is "305 72 737 456 282 307 519 724 13 505 193"
493             },
494             0xa021 => { #1
495             Name => 'WB_RGGBLevelsUncorrected',
496             Writable => 'int32u',
497             Count => 4,
498             Notes => 'these tags not corrected for WB_RGGBLevelsBlack',
499             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
500             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
501             },
502             0xa022 => { #1
503             Name => 'WB_RGGBLevelsAuto',
504             Writable => 'int32u',
505             Count => 4,
506             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-4)',
507             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,4)',
508             },
509             0xa023 => { #1
510             Name => 'WB_RGGBLevelsIlluminator1',
511             Writable => 'int32u',
512             Count => 4,
513             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-8)',
514             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,8)',
515             },
516             0xa024 => { #1
517             Name => 'WB_RGGBLevelsIlluminator2',
518             Writable => 'int32u',
519             Count => 4,
520             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-1)',
521             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,1)',
522             },
523             0xa025 => { # (PostAEGain?)
524             Name => 'DigitalGain', #IB
525             Writable => 'int32u',
526             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,6)',
527             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-6)',
528             },
529             0xa025 => { #IB
530             Name => 'HighlightLinearityLimit',
531             Writable => 'int32u',
532             },
533             0xa028 => { #2/PH
534             Name => 'WB_RGGBLevelsBlack',
535             Writable => 'int32s',
536             Count => 4,
537             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
538             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
539             },
540             0xa030 => { #1
541             Name => 'ColorMatrix',
542             Writable => 'int32s',
543             Count => 9,
544             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
545             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
546             },
547             0xa031 => { #1
548             Name => 'ColorMatrixSRGB',
549             Writable => 'int32s',
550             Count => 9,
551             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
552             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
553             },
554             0xa032 => { #1
555             Name => 'ColorMatrixAdobeRGB',
556             Writable => 'int32s',
557             Count => 9,
558             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
559             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
560             },
561             0xa033 => { #1
562             Name => 'CbCrMatrixDefault',
563             Writable => 'int32s',
564             Count => 4,
565             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
566             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
567             },
568             0xa034 => { #1
569             Name => 'CbCrMatrix',
570             Writable => 'int32s',
571             Count => 4,
572             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,4)',
573             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-4)',
574             },
575             0xa035 => { #1
576             Name => 'CbCrGainDefault',
577             Writable => 'int32u',
578             Count => 2,
579             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
580             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
581             },
582             0xa036 => { #1
583             Name => 'CbCrGain',
584             Writable => 'int32u',
585             Count => 2,
586             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-2)',
587             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,2)',
588             },
589             0xa040 => { #1
590             Name => 'ToneCurveSRGBDefault',
591             Writable => 'int32u',
592             Count => 23,
593             Notes => q{
594             first value gives the number of tone curve entries. This is followed by an
595             array of X coordinates then an array of Y coordinates
596             },
597             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,"-0")',
598             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",0)',
599             },
600             0xa041 => { #1
601             Name => 'ToneCurveAdobeRGBDefault',
602             Writable => 'int32u',
603             Count => 23,
604             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,"-0")',
605             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",0)',
606             },
607             0xa042 => { #1
608             Name => 'ToneCurveSRGB',
609             Writable => 'int32u',
610             Count => 23,
611             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,"-0")',
612             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",0)',
613             },
614             0xa043 => { #1
615             Name => 'ToneCurveAdobeRGB',
616             Writable => 'int32u',
617             Count => 23,
618             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,"-0")',
619             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",0)',
620             },
621             0xa048 => { #1
622             Name => 'RawData',
623             Unknown => 1,
624             Writable => 'int32s',
625             Count => 12,
626             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
627             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
628             },
629             0xa050 => { #1
630             Name => 'Distortion',
631             Unknown => 1,
632             Writable => 'int32s',
633             Count => 8,
634             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0)',
635             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0")',
636             },
637             0xa051 => { #1
638             Name => 'ChromaticAberration',
639             Unknown => 1,
640             Writable => 'int16u',
641             Count => 22,
642             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",-7,-3)',
643             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,7,3)',
644             },
645             0xa052 => { #1
646             Name => 'Vignetting',
647             Unknown => 1,
648             Writable => 'int16u',
649             Count => 15,
650             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,"-0")',
651             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",0)',
652             },
653             0xa053 => { #1
654             Name => 'VignettingCorrection',
655             Unknown => 1,
656             Writable => 'int16u',
657             Count => 15,
658             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,"-0")',
659             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",0)',
660             },
661             0xa054 => { #1
662             Name => 'VignettingSetting',
663             Unknown => 1,
664             Writable => 'int16u',
665             Count => 15,
666             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,0,"-0")',
667             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,"-0",0)',
668             },
669             0xa055 => { #1
670             Name => 'Samsung_Type2_0xa055', # (DistortionCamera1st?)
671             Unknown => 1,
672             Hidden => 1,
673             Writable => 'int32s',
674             Count => 8,
675             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,8)',
676             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-8)',
677             },
678             0xa056 => { #1
679             Name => 'Samsung_Type2_0xa056', # (DistortionCamera2nd?)
680             Unknown => 1,
681             Hidden => 1,
682             Writable => 'int32s',
683             Count => 8,
684             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,5)',
685             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-5)',
686             },
687             0xa057 => { #1
688             Name => 'Samsung_Type2_0xa057', # (DistortionCameraSetting?)
689             Unknown => 1,
690             Hidden => 1,
691             Writable => 'int32s',
692             Count => 8,
693             RawConv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,2)',
694             RawConvInv => 'Image::ExifTool::Samsung::Crypt($self,$val,$tagInfo,-2)',
695             },
696             # 0xa060 - rational64u (CISTemperature?)
697             # 0xa061 - int16u (Compression?)
698             );
699              
700             # orientation information (ref 6)
701             %Image::ExifTool::Samsung::OrientationInfo = (
702             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
703             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
704             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
705             WRITABLE => 1,
706             FORMAT => 'rational64s',
707             FIRST_ENTRY => 0,
708             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
709             NOTES => 'Camera orientation information written by the Gear 360 (SM-C200).',
710             0 => {
711             Name => 'YawAngle', #(NC)
712             Unknown => 1,
713             Notes => 'always zero',
714             },
715             1 => {
716             Name => 'PitchAngle',
717             Notes => 'upward tilt of rear camera in degrees',
718             },
719             2 => {
720             Name => 'RollAngle',
721             Notes => 'clockwise rotation of rear camera in degrees',
722             },
723             );
724              
725             # Picture Wizard information (ref 1)
726             %Image::ExifTool::Samsung::PictureWizard = (
727             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
728             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
729             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
730             WRITABLE => 1,
731             FORMAT => 'int16u',
732             FIRST_ENTRY => 0,
733             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
734             0 => {
735             Name => 'PictureWizardMode',
736             PrintConvColumns => 3,
737             PrintConv => { #3
738             0 => 'Standard',
739             1 => 'Vivid',
740             2 => 'Portrait',
741             3 => 'Landscape',
742             4 => 'Forest',
743             5 => 'Retro',
744             6 => 'Cool',
745             7 => 'Calm',
746             8 => 'Classic',
747             9 => 'Custom1',
748             10 => 'Custom2',
749             11 => 'Custom3',
750             255 => 'n/a', #PH
751             },
752             },
753             1 => 'PictureWizardColor',
754             2 => {
755             Name => 'PictureWizardSaturation',
756             ValueConv => '$val - 4',
757             ValueConvInv => '$val + 4',
758             },
759             3 => {
760             Name => 'PictureWizardSharpness',
761             ValueConv => '$val - 4',
762             ValueConvInv => '$val + 4',
763             },
764             4 => {
765             Name => 'PictureWizardContrast',
766             ValueConv => '$val - 4',
767             ValueConvInv => '$val + 4',
768             },
769             );
770              
771             # INFO tags in Samsung MP4 videos (ref PH)
772             %Image::ExifTool::Samsung::INFO = (
773             PROCESS_PROC => \&ProcessINFO,
774             GROUPS => { 0 => 'MakerNotes', 2 => 'Video' },
775             NOTES => q{
776             This information is found in MP4 videos from Samsung models such as the
777             SMX-C20N.
778             },
779             EFCT => 'Effect', # (guess)
780             QLTY => 'Quality',
781             # MDEL - value: 0
782             # ASPT - value: 1, 2
783             );
784              
785             # Samsung MP4 TAGS information (PH - from WP10 sample)
786             # --> very similar to Sanyo MP4 information
787             %Image::ExifTool::Samsung::MP4 = (
788             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
789             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
790             NOTES => q{
791             This information is found in Samsung MP4 videos from models such as the
792             WP10.
793             },
794             0x00 => {
795             Name => 'Make',
796             Format => 'string[24]',
797             PrintConv => 'ucfirst(lc($val))',
798             },
799             0x18 => {
800             Name => 'Model',
801             Description => 'Camera Model Name',
802             Format => 'string[16]',
803             },
804             0x2e => { #(NC)
805             Name => 'ExposureTime',
806             Format => 'int32u',
807             ValueConv => '$val ? 10 / $val : 0',
808             PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
809             },
810             0x32 => {
811             Name => 'FNumber',
812             Format => 'rational64u',
813             PrintConv => 'sprintf("%.1f",$val)',
814             },
815             0x3a => { #(NC)
816             Name => 'ExposureCompensation',
817             Format => 'rational64s',
818             PrintConv => '$val ? sprintf("%+.1f", $val) : 0',
819             },
820             0x6a => {
821             Name => 'ISO',
822             Format => 'int32u',
823             },
824             0x7d => {
825             Name => 'Software',
826             Format => 'string[32]',
827             # (these tags are not at a constant offset for Olympus/Sanyo videos,
828             # so just to be safe use this to validate subsequent tags)
829             RawConv => q{
830             $val =~ /^SAMSUNG/ or return undef;
831             $$self{SamsungMP4} = 1;
832             return $val;
833             },
834             },
835             0xf4 => {
836             Name => 'Thumbnail',
837             Condition => '$$self{SamsungMP4}',
838             SubDirectory => {
839             TagTable => 'Image::ExifTool::Samsung::Thumbnail',
840             Base => '$start',
841             },
842             },
843             );
844              
845             # thumbnail image information found in MP4 videos (similar in Olympus,Samsung,Sanyo)
846             %Image::ExifTool::Samsung::Thumbnail = (
847             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
848             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
849             FIRST_ENTRY => 0,
850             FORMAT => 'int32u',
851             1 => 'ThumbnailWidth',
852             2 => 'ThumbnailHeight',
853             3 => 'ThumbnailLength',
854             4 => { Name => 'ThumbnailOffset', IsOffset => 1 },
855             );
856              
857             # Samsung MP4 @sec information (PH - from WB30F sample)
858             %Image::ExifTool::Samsung::sec = (
859             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
860             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
861             NOTES => q{
862             This information is found in the @sec atom of Samsung MP4 videos from models
863             such as the WB30F.
864             },
865             0x00 => {
866             Name => 'Make',
867             Format => 'string[32]',
868             PrintConv => 'ucfirst(lc($val))',
869             },
870             0x20 => {
871             Name => 'Model',
872             Description => 'Camera Model Name',
873             Format => 'string[32]',
874             },
875             0x200 => { Name => 'ThumbnailWidth', Format => 'int32u' },
876             0x204 => { Name => 'ThumbnailHeight', Format => 'int32u' },
877             0x208 => { Name => 'ThumbnailLength', Format => 'int32u' }, # (2 bytes too long in my sample)
878             0x20c => {
879             Name => 'ThumbnailImage',
880             Groups => { 2 => 'Preview' },
881             Format => 'undef[$val{0x208}]',
882             Notes => 'the THM image, embedded metadata is extracted as the first sub-document',
883             SetBase => 1,
884             RawConv => q{
885             my $pt = $self->ValidateImage(\$val, $tag);
886             if ($pt) {
887             $$self{BASE} += 0x20c;
888             $$self{DOC_NUM} = ++$$self{DOC_COUNT};
889             $self->ExtractInfo($pt, { ReEntry => 1 });
890             $$self{DOC_NUM} = 0;
891             }
892             return $pt;
893             },
894             },
895             );
896              
897             # Samsung MP4 smta information (PH - from SM-C101 sample)
898             %Image::ExifTool::Samsung::smta = (
899             GROUPS => { 0 => 'MakerNotes', 2 => 'Video' },
900             NOTES => q{
901             This information is found in the smta atom of Samsung MP4 videos from models
902             such as the Galaxy S4.
903             },
904             svss => {
905             Name => 'SamsungSvss',
906             SubDirectory => { TagTable => 'Image::ExifTool::Samsung::svss' },
907             },
908             mdln => 'SamsungModel', #PH (Samsung SM-A136U, etc)
909             # swtr - 4 bytes, all zero
910             # scid - 8 bytes, all zero
911             # saut - 4 or 6 bytes, all zero
912             );
913              
914             # Samsung MP4 svss information (PH - from SM-C101 sample)
915             %Image::ExifTool::Samsung::svss = (
916             GROUPS => { 0 => 'MakerNotes', 2 => 'Video' },
917             NOTES => q{
918             This information is found in the svss atom of Samsung MP4 videos from models
919             such as the Galaxy S4.
920             },
921             # junk - 10240 bytes, all zero
922             );
923              
924             # thumbnail image information found in some MP4 videos
925             %Image::ExifTool::Samsung::Thumbnail2 = (
926             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
927             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
928             FIRST_ENTRY => 0,
929             FORMAT => 'int32u',
930             1 => 'ThumbnailWidth',
931             2 => 'ThumbnailHeight',
932             3 => 'ThumbnailLength',
933             4 => { Name => 'ThumbnailOffset', IsOffset => 1 },
934             );
935              
936             # information extracted from "ssuniqueid\0" APP5 (ref PH)
937             %Image::ExifTool::Samsung::APP5 = (
938             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
939             ssuniqueid => {
940             Name => 'UniqueID',
941             # 32 bytes - some sort of serial number?
942             ValueConv => 'unpack("H*",$val)',
943             },
944             );
945              
946             # information extracted from Samsung trailer (ie. Samsung SM-T805 "Sound & Shot" JPEG) (ref PH)
947             # NOTE: These tags may use $$self{SamsungTagName} in a Condition statement
948             # if necessary to differentiate tags with the same ID but different names
949             %Image::ExifTool::Samsung::Trailer = (
950             GROUPS => { 0 => 'MakerNotes', 2 => 'Other' },
951             VARS => { ID_FMT => 'none' },
952             PROCESS_PROC => \&ProcessSamsung,
953             TAG_PREFIX => 'SamsungTrailer',
954             PRIORITY => 0, # (first one takes priority so DepthMapWidth/Height match first DepthMapData)
955             NOTES => q{
956             Tags extracted from the SEFT trailer of JPEG and PNG images written when
957             using certain features (such as "Sound & Shot" or "Shot & More") from
958             Samsung models such as the Galaxy S4 and Tab S, and from the 'sefd' atom in
959             HEIC images from models such as the S10+.
960             },
961             '0x0001-name' => 'EmbeddedImageName', # ("DualShot_1","DualShot_2","SingleShot")
962             '0x0001' => [
963             {
964             Name => 'EmbeddedImage',
965             Condition => '$$self{SamsungTagName} ne "DualShot_2"',
966             Groups => { 2 => 'Preview' },
967             Binary => 1,
968             },
969             {
970             Name => 'EmbeddedImage2',
971             Groups => { 2 => 'Preview' },
972             Binary => 1,
973             },
974             # (have also seen the string "BOKEH" here (SM-A226B)
975             ],
976             '0x0100-name' => 'EmbeddedAudioFileName', # ("SoundShot_000")
977             '0x0100' => { Name => 'EmbeddedAudioFile', Groups => { 2 => 'Audio' }, Binary => 1 },
978             '0x0201-name' => 'SurroundShotVideoName', # ("Interactive_Panorama_000")
979             '0x0201' => { Name => 'SurroundShotVideo', Groups => { 2 => 'Video' }, Binary => 1 },
980             # 0x0800-name - seen 'SoundShot_Meta_Info'
981             # 0x0800 - unknown (29 bytes) (contains already-extracted EmbeddedAudioFileName)
982             # 0x0830-name - seen '1165724808.pre'
983             # 0x0830 - unknown (164004 bytes)
984             # 0x08c0-name - seen 'Auto_Enhance_Info' #forum16086
985             # 0x08d0-name - seen 'Interactive_Panorama_Info'
986             # 0x08d0 - unknown (7984 bytes)
987             # 0x08e0-name - seen 'Panorama_Shot_Info'
988             # 0x08e0 - string, seen 'PanoramaShot'
989             # 0x08e1-name - seen 'Motion_Panorama_Info'
990             # 0x0910-name - seen 'Front_Cam_Selfie_Info'
991             # 0x0910 - string, seen 'Front_Cam_Selfie_Info'
992             # 0x09e0-name - seen 'Burst_Shot_Info'
993             # 0x09e0 - string, seen '489489125'
994             # 0x09e1-name - seen 'BurstShot_Best_Photo_Info' #forum16086
995             # 0x09f0-name - seen 'Pro_Mode_Info' #forum16086
996             # 0x0a01-name - seen 'Image_UTC_Data'
997             '0x0a01' => { #forum7161
998             Name => 'TimeStamp',
999             Groups => { 2 => 'Time' },
1000             ValueConv => 'ConvertUnixTime($val / 1e3, 1, 3)',
1001             PrintConv => '$self->ConvertDateTime($val)',
1002             },
1003             '0x0a20-name' => 'DualCameraImageName', # ("FlipPhoto_002")
1004             '0x0a20' => { Name => 'DualCameraImage', Groups => { 2 => 'Preview' }, Binary => 1 },
1005             '0x0a30-name' => 'EmbeddedVideoType', # ("MotionPhoto_Data")
1006             # Note: A duplicate of this video may be extracted as MotionPhotoVideo from
1007             # the Google trailer, but keep this copy named as EmbeddedVideoFile
1008             # for backward compatibility and to avoid confusion due to extracting
1009             # multiple tags with the same name
1010             '0x0a30' => [{
1011             Name => 'EmbeddedVideoOffsetSize',
1012             # (have seen 12-byte data starting with "mpv2" that contains
1013             # absolute file offset and size of embedded video)
1014             Condition => 'length $$valPt == 12',
1015             ValueConv => 'join(" ", unpack("x4N2", $val))',
1016             },{ #forum7161
1017             Name => 'EmbeddedVideoFile',
1018             Groups => { 2 => 'Video' },
1019             Binary => 1,
1020             }],
1021             # 0x0a31-name - seen MotionPhoto_Version
1022             '0x0a31' => 'SamsungMotionPhotoVersion', # (to distinguish from XMP-GCamera:MotionPhotoVersion)
1023             '0x0a33' => { # seen MotionPhoto_AutoPlay
1024             Name => 'MotionPhotoAutoPlayVideo',
1025             Groups => { 2 => 'Video' },
1026             Binary => 1,
1027             },
1028             # 0x0a41-name - seen 'BackupRestore_Data' #forum16086
1029             # 0x0aa1-name - seen 'MCC_Data'
1030             # 0x0aa1 - seen '204','222','234','302','429'
1031             '0x0aa1' => {
1032             Name => 'MCCData',
1033             Groups => { 2 => 'Location' },
1034             PrintConv => {
1035             202 => 'Greece (202)',
1036             204 => 'Netherlands (204)',
1037             206 => 'Belgium (206)',
1038             208 => 'France (208)',
1039             212 => 'Monaco (212)',
1040             213 => 'Andorra (213)',
1041             214 => 'Spain (214)',
1042             216 => 'Hungary (216)',
1043             218 => 'Bosnia & Herzegov. (218)',
1044             219 => 'Croatia (219)',
1045             220 => 'Serbia (220)',
1046             221 => 'Kosovo (221)',
1047             222 => 'Italy (222)',
1048             226 => 'Romania (226)',
1049             228 => 'Switzerland (228)',
1050             230 => 'Czech Rep. (230)',
1051             231 => 'Slovakia (231)',
1052             232 => 'Austria (232)',
1053             234 => 'United Kingdom (234)',
1054             235 => 'United Kingdom (235)',
1055             238 => 'Denmark (238)',
1056             240 => 'Sweden (240)',
1057             242 => 'Norway (242)',
1058             244 => 'Finland (244)',
1059             246 => 'Lithuania (246)',
1060             247 => 'Latvia (247)',
1061             248 => 'Estonia (248)',
1062             250 => 'Russian Federation (250)',
1063             255 => 'Ukraine (255)',
1064             257 => 'Belarus (257)',
1065             259 => 'Moldova (259)',
1066             260 => 'Poland (260)',
1067             262 => 'Germany (262)',
1068             266 => 'Gibraltar (266)',
1069             268 => 'Portugal (268)',
1070             270 => 'Luxembourg (270)',
1071             272 => 'Ireland (272)',
1072             274 => 'Iceland (274)',
1073             276 => 'Albania (276)',
1074             278 => 'Malta (278)',
1075             280 => 'Cyprus (280)',
1076             282 => 'Georgia (282)',
1077             283 => 'Armenia (283)',
1078             284 => 'Bulgaria (284)',
1079             286 => 'Turkey (286)',
1080             288 => 'Faroe Islands (288)',
1081             289 => 'Abkhazia (289)',
1082             290 => 'Greenland (290)',
1083             292 => 'San Marino (292)',
1084             293 => 'Slovenia (293)',
1085             294 => 'Macedonia (294)',
1086             295 => 'Liechtenstein (295)',
1087             297 => 'Montenegro (297)',
1088             302 => 'Canada (302)',
1089             308 => 'St. Pierre & Miquelon (308)',
1090             310 => 'United States / Guam (310)',
1091             311 => 'United States / Guam (311)',
1092             312 => 'United States (312)',
1093             316 => 'United States (316)',
1094             330 => 'Puerto Rico (330)',
1095             334 => 'Mexico (334)',
1096             338 => 'Jamaica (338)',
1097             340 => 'French Guiana / Guadeloupe / Martinique (340)',
1098             342 => 'Barbados (342)',
1099             344 => 'Antigua and Barbuda (344)',
1100             346 => 'Cayman Islands (346)',
1101             348 => 'British Virgin Islands (348)',
1102             350 => 'Bermuda (350)',
1103             352 => 'Grenada (352)',
1104             354 => 'Montserrat (354)',
1105             356 => 'Saint Kitts and Nevis (356)',
1106             358 => 'Saint Lucia (358)',
1107             360 => 'St. Vincent & Gren. (360)',
1108             362 => 'Bonaire, Sint Eustatius and Saba / Curacao / Netherlands Antilles (362)',
1109             363 => 'Aruba (363)',
1110             364 => 'Bahamas (364)',
1111             365 => 'Anguilla (365)',
1112             366 => 'Dominica (366)',
1113             368 => 'Cuba (368)',
1114             370 => 'Dominican Republic (370)',
1115             372 => 'Haiti (372)',
1116             374 => 'Trinidad and Tobago (374)',
1117             376 => 'Turks and Caicos Islands / US Virgin Islands (376)',
1118             400 => 'Azerbaijan (400)',
1119             401 => 'Kazakhstan (401)',
1120             402 => 'Bhutan (402)',
1121             404 => 'India (404)',
1122             405 => 'India (405)',
1123             410 => 'Pakistan (410)',
1124             412 => 'Afghanistan (412)',
1125             413 => 'Sri Lanka (413)',
1126             414 => 'Myanmar (Burma) (414)',
1127             415 => 'Lebanon (415)',
1128             416 => 'Jordan (416)',
1129             417 => 'Syrian Arab Republic (417)',
1130             418 => 'Iraq (418)',
1131             419 => 'Kuwait (419)',
1132             420 => 'Saudi Arabia (420)',
1133             421 => 'Yemen (421)',
1134             422 => 'Oman (422)',
1135             424 => 'United Arab Emirates (424)',
1136             425 => 'Israel / Palestinian Territory (425)',
1137             426 => 'Bahrain (426)',
1138             427 => 'Qatar (427)',
1139             428 => 'Mongolia (428)',
1140             429 => 'Nepal (429)',
1141             430 => 'United Arab Emirates (430)',
1142             431 => 'United Arab Emirates (431)',
1143             432 => 'Iran (432)',
1144             434 => 'Uzbekistan (434)',
1145             436 => 'Tajikistan (436)',
1146             437 => 'Kyrgyzstan (437)',
1147             438 => 'Turkmenistan (438)',
1148             440 => 'Japan (440)',
1149             441 => 'Japan (441)',
1150             450 => 'South Korea (450)',
1151             452 => 'Viet Nam (452)',
1152             454 => 'Hongkong, China (454)',
1153             455 => 'Macao, China (455)',
1154             456 => 'Cambodia (456)',
1155             457 => 'Laos P.D.R. (457)',
1156             460 => 'China (460)',
1157             466 => 'Taiwan (466)',
1158             467 => 'North Korea (467)',
1159             470 => 'Bangladesh (470)',
1160             472 => 'Maldives (472)',
1161             502 => 'Malaysia (502)',
1162             505 => 'Australia (505)',
1163             510 => 'Indonesia (510)',
1164             514 => 'Timor-Leste (514)',
1165             515 => 'Philippines (515)',
1166             520 => 'Thailand (520)',
1167             525 => 'Singapore (525)',
1168             528 => 'Brunei Darussalam (528)',
1169             530 => 'New Zealand (530)',
1170             537 => 'Papua New Guinea (537)',
1171             539 => 'Tonga (539)',
1172             540 => 'Solomon Islands (540)',
1173             541 => 'Vanuatu (541)',
1174             542 => 'Fiji (542)',
1175             544 => 'American Samoa (544)',
1176             545 => 'Kiribati (545)',
1177             546 => 'New Caledonia (546)',
1178             547 => 'French Polynesia (547)',
1179             548 => 'Cook Islands (548)',
1180             549 => 'Samoa (549)',
1181             550 => 'Micronesia (550)',
1182             552 => 'Palau (552)',
1183             553 => 'Tuvalu (553)',
1184             555 => 'Niue (555)',
1185             602 => 'Egypt (602)',
1186             603 => 'Algeria (603)',
1187             604 => 'Morocco (604)',
1188             605 => 'Tunisia (605)',
1189             606 => 'Libya (606)',
1190             607 => 'Gambia (607)',
1191             608 => 'Senegal (608)',
1192             609 => 'Mauritania (609)',
1193             610 => 'Mali (610)',
1194             611 => 'Guinea (611)',
1195             612 => 'Ivory Coast (612)',
1196             613 => 'Burkina Faso (613)',
1197             614 => 'Niger (614)',
1198             615 => 'Togo (615)',
1199             616 => 'Benin (616)',
1200             617 => 'Mauritius (617)',
1201             618 => 'Liberia (618)',
1202             619 => 'Sierra Leone (619)',
1203             620 => 'Ghana (620)',
1204             621 => 'Nigeria (621)',
1205             622 => 'Chad (622)',
1206             623 => 'Central African Rep. (623)',
1207             624 => 'Cameroon (624)',
1208             625 => 'Cape Verde (625)',
1209             626 => 'Sao Tome & Principe (626)',
1210             627 => 'Equatorial Guinea (627)',
1211             628 => 'Gabon (628)',
1212             629 => 'Congo, Republic (629)',
1213             630 => 'Congo, Dem. Rep. (630)',
1214             631 => 'Angola (631)',
1215             632 => 'Guinea-Bissau (632)',
1216             633 => 'Seychelles (633)',
1217             634 => 'Sudan (634)',
1218             635 => 'Rwanda (635)',
1219             636 => 'Ethiopia (636)',
1220             637 => 'Somalia (637)',
1221             638 => 'Djibouti (638)',
1222             639 => 'Kenya (639)',
1223             640 => 'Tanzania (640)',
1224             641 => 'Uganda (641)',
1225             642 => 'Burundi (642)',
1226             643 => 'Mozambique (643)',
1227             645 => 'Zambia (645)',
1228             646 => 'Madagascar (646)',
1229             647 => 'Reunion (647)',
1230             648 => 'Zimbabwe (648)',
1231             649 => 'Namibia (649)',
1232             650 => 'Malawi (650)',
1233             651 => 'Lesotho (651)',
1234             652 => 'Botswana (652)',
1235             653 => 'Swaziland (653)',
1236             654 => 'Comoros (654)',
1237             655 => 'South Africa (655)',
1238             657 => 'Eritrea (657)',
1239             659 => 'South Sudan (659)',
1240             702 => 'Belize (702)',
1241             704 => 'Guatemala (704)',
1242             706 => 'El Salvador (706)',
1243             708 => 'Honduras (708)',
1244             710 => 'Nicaragua (710)',
1245             712 => 'Costa Rica (712)',
1246             714 => 'Panama (714)',
1247             716 => 'Peru (716)',
1248             722 => 'Argentina Republic (722)',
1249             724 => 'Brazil (724)',
1250             730 => 'Chile (730)',
1251             732 => 'Colombia (732)',
1252             734 => 'Venezuela (734)',
1253             736 => 'Bolivia (736)',
1254             738 => 'Guyana (738)',
1255             740 => 'Ecuador (740)',
1256             744 => 'Paraguay (744)',
1257             746 => 'Suriname (746)',
1258             748 => 'Uruguay (748)',
1259             750 => 'Falkland Islands (Malvinas) (750)',
1260             901 => 'International Networks / Satellite Networks (901)',
1261             },
1262             },
1263             # 0x0ab0-name - seen 'DualShot_Meta_Info'
1264             '0x0ab1-name' => {
1265             Name => 'DepthMapName',
1266             # seen 'DualShot_DepthMap_1' (SM-N950U), DualShot_DepthMap_5 (SM-G998W)
1267             RawConv => '$$self{DepthMapName} = $val',
1268             },
1269             '0x0ab1' => [
1270             {
1271             Name => 'DepthMapData',
1272             Condition => '$$self{DepthMapName} eq "DualShot_DepthMap_1"',
1273             Binary => 1,
1274             },{
1275             Name => 'DepthMapData2',
1276             Binary => 1,
1277             },
1278             ],
1279             # 0x0ab3-name - seen 'DualShot_Extra_Info' (SM-N950U)
1280             '0x0ab3' => { # (SM-N950U)
1281             Name => 'DualShotExtra',
1282             SubDirectory => { TagTable => 'Image::ExifTool::Samsung::DualShotExtra' },
1283             },
1284             # 0x0ab4-name - seen 'DualShot_Core_Info' #forum16086
1285             # 0x0ac0-name - seen 'ZoomInOut_Info' (SM-N950U)
1286             # 0x0ac0 - 2048 bytes of interesting stuff including firmware version? (SM-N950U)
1287             # 0x0b30-name - seen 'Camera_Sticker_Info' #forum16086
1288             '0x0b40' => { # (SM-N975X front camera)
1289             Name => 'SingleShotMeta',
1290             SubDirectory => { TagTable => 'Image::ExifTool::Samsung::SingleShotMeta' },
1291             # (have also see the string "BOKEH_INFO" here (SM-A226B)
1292             },
1293             # 0x0b41-name - seen 'SingeShot_DepthMap_1' (Yes, "Singe") (SM-N975X front camera)
1294             '0x0b41' => { Name => 'SingleShotDepthMap', Binary => 1 },
1295             # 0x0b51-name - seen 'Intelligent_PhotoEditor_Data' #forum16086
1296             # 0x0b60-name - seen 'UltraWide_PhotoEditor_Data' #forum16086
1297             # 0x0b90-name - seen 'Document_Scan_Info' #forum16086
1298             # 0x0ba1-name - seen 'Original_Path_Hash_Key', 'PhotoEditor_Re_Edit_Data', 'deco_doodle_bitmap', 'deco_sticker_bitmap', 'deco_text_bitmap','PhotoEditor_Re_Edit_Data'
1299             '0x0ba1' => [{
1300             Name => 'ReEditData',
1301             Condition => '$$self{SamsungTagName} eq "PhotoEditor_Re_Edit_Data"',
1302             SubDirectory => { TagTable => 'Image::ExifTool::Samsung::ReEditData' },
1303             },{
1304             Name => 'OriginalPathHashKey',
1305             Condition => '$$self{SamsungTagName} eq "Original_Path_Hash_Key"',
1306             }],
1307             # 0x0ba2-name - seen 'Copy_Available_Edit_Info' #forum16086
1308             # 0x0bc0-name - seen 'Single_Relighting_Bokeh_Info' #forum16086
1309             # 0x0bd0-name - seen 'Dual_Relighting_Bokeh_Info' #forum16086
1310             # 0x0be0-name - seen 'Livefocus_JDM_Info' #forum16086
1311             # 0x0bf0-name - seen 'Remaster_Info' #forum16086
1312             '0x0bf0' => 'RemasterInfo', #forum16086/16242
1313             # 0x0c21-name - seen 'Portrait_Effect_Info' #forum16086
1314             # 0x0c51-name - seen 'Samsung_Capture_Info' #forum16086
1315             '0x0c51' => 'SamsungCaptureInfo', #forum16086/16242
1316             # 0x0c61-name - seen 'Camera_Capture_Mode_Info' #forum16086
1317             # 0x0c71-name - seen 'Pro_White_Balance_Info' #forum16086
1318             # 0x0c81-name - seen 'Watermark_Info' #forum16086
1319             # 0x0cc1-name - seen 'Color_Display_P3' #forum16086
1320             # 0x0cd2-name - seen 'Photo_HDR_Info' #forum16086
1321             # 0x0ce1-name - seen 'Gallery_DC_Data' #forum16086
1322             # 0x0d01-name - seen 'Camera_Scene_Info', 'Camera_Scene_Info2', 'Camera_Scene_Info3' #forum16086
1323             # 0x0d11-name - seen 'Video_Snapshot_Info' #forum16086
1324             # 0x0d21-name - seen 'Camera_Scene_Info' #forum16086
1325             # 0x0d31-name - seen 'Food_Blur_Effect_Info' #forum16086
1326             '0x0d91' => { #forum16086/16242
1327             Name => 'PEg_Info',
1328             Description => 'PEg Info',
1329             SubDirectory => { TagTable => 'Image::ExifTool::Samsung::PEgInfo' },
1330             },
1331             # 0x0da1-name - seen 'Captured_App_Info' #forum16086
1332             # 0xa050-name - seen 'Jpeg360_2D_Info' (Samsung Gear 360)
1333             # 0xa050 - seen 'Jpeg3602D' (Samsung Gear 360)
1334             # 0x0c61-name - seen 'Camera_Capture_Mode_Info'
1335             # 0x0c61 - seen '1'
1336             # 0x0c81-name - seen 'Watermark_Info'
1337             # 0x0ce1-name - seen 'Gallery_DC_Data'
1338             # 0x0ce1 - seen '0,109,2,19010102,4000,3000,0,0,0,0;116.284004;1.0'
1339             # 0x0e41-name - seen 'Video_Edited_UTC_Offset'
1340             # 0x0e41 - seen '+0800'
1341             '0x0e41' => {
1342             Name => 'VideoEditedTimeZone',
1343             Groups => { 2 => 'Time' },
1344             },
1345             );
1346              
1347             # DualShot Extra Info (ref PH)
1348             %Image::ExifTool::Samsung::DualShotExtra = (
1349             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1350             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
1351             FIRST_ENTRY => 0,
1352             FORMAT => 'int32u',
1353             # This is a pain, but the DepthMapWidth/Height move around in this record.
1354             # In all of my samples so far, the bytes "01 00 ff ff" precede these tags.
1355             # I have seen this byte sequence at offsets 32, 60, 64 and 68, so look for
1356             # it in bytes 32-95, and use its location to adjust the tag positions
1357             8 => {
1358             Name => 'DualShotDummy',
1359             Format => 'undef[64]',
1360             Hidden => 1,
1361             Hook => q{
1362             if ($size >= 96) {
1363             my $tmp = substr($$dataPt, $pos, 64);
1364             # (have seen 0x01,0x03 and 0x07)
1365             if ($tmp =~ /[\x01-\x09]\0\xff\xff/g and not pos($tmp) % 4) {
1366             $$self{DepthMapTagPos} = pos($tmp);
1367             $varSize += $$self{DepthMapTagPos} - 32;
1368             }
1369             }
1370             },
1371             RawConv => 'undef', # not a real tag
1372             },
1373             16 => {
1374             Name => 'DepthMapWidth',
1375             Condition => '$$self{DepthMapTagPos}',
1376             Notes => 'index varies depending on model',
1377             },
1378             17 => {
1379             Name => 'DepthMapHeight',
1380             Condition => '$$self{DepthMapTagPos}',
1381             Notes => 'index varies depending on model',
1382             },
1383             );
1384              
1385             # SingleShot Meta Info (ref PH) (SM-N975X front camera)
1386             %Image::ExifTool::Samsung::SingleShotMeta = (
1387             PROCESS_PROC => \&ProcessSamsungMeta,
1388             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
1389             inputWidth => { },
1390             inputHeight => { },
1391             outputWidth => { },
1392             outputHeight => { },
1393             segWidth => { },
1394             segHeight => { },
1395             depthSWWidth => { },
1396             depthSWHeight => { },
1397             depthHWWidth => { },
1398             depthHWHeight => { },
1399             flipStatus => { },
1400             lensFacing => { },
1401             deviceOrientation => { },
1402             objectOrientation => { },
1403             isArtBokeh => { },
1404             beautyRetouchLevel => { },
1405             beautyColorLevel => { },
1406             effectType => { },
1407             effectStrength => { },
1408             blurStrength => { },
1409             spinStrength => { },
1410             zoomStrength => { },
1411             colorpopStrength => { },
1412             monoStrength => { },
1413             sidelightStrength => { },
1414             vintageStrength => { },
1415             bokehShape => { },
1416             perfMode => { },
1417             );
1418              
1419             %Image::ExifTool::Samsung::ReEditData = (
1420             GROUPS => { 0 => 'JSON', 2 => 'Image' },
1421             PROCESS_PROC => \&Image::ExifTool::JSON::ProcessJSON,
1422             VARS => { LONG_TAGS => 2 },
1423             originalPath => { },
1424             representativeFrameLoc => { },
1425             startMotionVideo => { },
1426             endMotionVideo => { },
1427             isMotionVideoMute => { },
1428             isTrimMotionVideo => { },
1429             clipInfoValue => { SubDirectory => { TagTable => 'Image::ExifTool::Samsung::ClipInfo' } },
1430             toneValue => { SubDirectory => { TagTable => 'Image::ExifTool::Samsung::ToneInfo' } },
1431             effectValue => { SubDirectory => { TagTable => 'Image::ExifTool::Samsung::EffectInfo' } },
1432             portraitEffectValue => { SubDirectory => { TagTable => 'Image::ExifTool::Samsung::PortraitEffect' } },
1433             isBlending => { },
1434             isNotReEdit => { },
1435             sepVersion => { Name => 'SEPVersion' },
1436             ndeVersion => { Name => 'NDEVersion' },
1437             reSize => { },
1438             isScaleAI => { },
1439             rotation => { },
1440             adjustmentValue => { },
1441             isApplyShapeCorrection => { },
1442             isNewReEditOnly => { },
1443             isDecoReEditOnly => { },
1444             isAIFilterReEditOnly=> { },
1445             );
1446              
1447             %Image::ExifTool::Samsung::ClipInfo = (
1448             GROUPS => { 0 => 'JSON', 2 => 'Image' },
1449             PROCESS_PROC => \&Image::ExifTool::JSON::ProcessJSON,
1450             mCenterX => { Name => 'ClipCenterX' },
1451             mCenterY => { Name => 'ClipCenterY' },
1452             mWidth => { Name => 'ClipWidth' },
1453             mHeight => { Name => 'ClipHeight' },
1454             mRotation => { Name => 'ClipRotation' },
1455             mRotate => { Name => 'ClipRotate' },
1456             mHFlip => { Name => 'ClipHFlip' },
1457             mVFlip => { Name => 'ClipVFlip' },
1458             mRotationEffect => { Name => 'ClipRotationEffect' },
1459             mRotateEffect => { Name => 'ClipRotateEffect' },
1460             mHFlipEffect => { Name => 'ClipHFlipEffect' },
1461             mVFlipEffect => { Name => 'ClipVFlipEffect' },
1462             mHozPerspective => { Name => 'ClipHozPerspective' },
1463             mVerPerspective => { Name => 'ClipVerPerspective' },
1464             );
1465              
1466             %Image::ExifTool::Samsung::ToneInfo = (
1467             GROUPS => { 0 => 'JSON', 2 => 'Image' },
1468             PROCESS_PROC => \&Image::ExifTool::JSON::ProcessJSON,
1469             brightness => { },
1470             exposure => { },
1471             contrast => { },
1472             saturation => { },
1473             hue => { },
1474             wbMode => { Name => 'WBMode' },
1475             wbTemperature => { Name => 'WBTemperature' },
1476             tint => { },
1477             shadow => { },
1478             highlight => { },
1479             lightbalance => { },
1480             sharpness => { },
1481             definition => { },
1482             isBrightnessIPE => { },
1483             isExposureIPE => { },
1484             isContrastIPE => { },
1485             isSaturationIPE => { },
1486             );
1487              
1488             %Image::ExifTool::Samsung::EffectInfo = (
1489             GROUPS => { 0 => 'JSON', 2 => 'Image' },
1490             PROCESS_PROC => \&Image::ExifTool::JSON::ProcessJSON,
1491             filterIndication=> { },
1492             alphaValue => { },
1493             filterType => { },
1494             );
1495              
1496             %Image::ExifTool::Samsung::PortraitEffect = (
1497             GROUPS => { 0 => 'JSON', 2 => 'Image' },
1498             PROCESS_PROC => \&Image::ExifTool::JSON::ProcessJSON,
1499             VARS => { LONG_TAGS => 1 },
1500             effectId => { Name => 'PortraitEffectID' },
1501             effectLevel => { Name => 'PortraitEffectLevel' },
1502             exifRotation => { Name => 'PortraitExifRotation' },
1503             lightLevel => { Name => 'PortraitLightLevel' },
1504             touchX => { Name => 'PortraitTouchX' },
1505             touchY => { Name => 'PortraitTouchY' },
1506             refocusX => { Name => 'PortraitRefocusX' },
1507             refocusY => { Name => 'PortraitRefocusY' },
1508             effectIdOriginal => { Name => 'PortraitEffectIDOriginal' },
1509             effectLevelOriginal => { Name => 'EffectLevelOriginal' },
1510             lightLevelOriginal => { Name => 'LightLevelOriginal' },
1511             touchXOriginal => { },
1512             touchYOriginal => { },
1513             refocusXOriginal=> { },
1514             refocusYOriginal=> { },
1515             waterMarkRemoved=> { Name => 'WaterMarkRemoved' },
1516             waterMarkRemovedOriginal => { Name => 'WaterMarkRemovedOriginal' },
1517             );
1518              
1519             %Image::ExifTool::Samsung::PEgInfo = (
1520             GROUPS => { 0 => 'JSON', 2 => 'Image' },
1521             PROCESS_PROC => \&Image::ExifTool::JSON::ProcessJSON,
1522             genImageVersion => { },
1523             connectorType => { },
1524             );
1525              
1526             # Samsung composite tags
1527             %Image::ExifTool::Samsung::Composite = (
1528             GROUPS => { 2 => 'Image' },
1529             WB_RGGBLevels => {
1530             Require => {
1531             0 => 'WB_RGGBLevelsUncorrected',
1532             1 => 'WB_RGGBLevelsBlack',
1533             },
1534             ValueConv => q{
1535             my @a = split ' ', $val[0];
1536             my @b = split ' ', $val[1];
1537             $a[$_] -= $b[$_] foreach 0..$#a;
1538             return "@a";
1539             },
1540             },
1541             DepthMapTiff => {
1542             Require => {
1543             0 => 'DepthMapData',
1544             1 => 'DepthMapWidth',
1545             2 => 'DepthMapHeight',
1546             },
1547             ValueConv => q{
1548             return undef unless length ${$val[0]} == $val[1] * $val[2];
1549             my $tiff = MakeTiffHeader($val[1],$val[2],1,8) . ${$val[0]};
1550             return \$tiff;
1551             },
1552             },
1553             SingleShotDepthMapTiff => {
1554             Require => {
1555             0 => 'SingleShotDepthMap',
1556             1 => 'SegWidth',
1557             2 => 'SegHeight',
1558             },
1559             ValueConv => q{
1560             return undef unless length ${$val[0]} == $val[1] * $val[2];
1561             my $tiff = MakeTiffHeader($val[1],$val[2],1,8) . ${$val[0]};
1562             return \$tiff;
1563             },
1564             },
1565             );
1566              
1567             # add our composite tags
1568             Image::ExifTool::AddCompositeTags('Image::ExifTool::Samsung');
1569              
1570             #------------------------------------------------------------------------------
1571             # Encrypt/Decrypt NX10 information
1572             # Inputs: 0) ExifTool ref, 1) value as a string of integers,
1573             # 2) tagInfo hash ref, 3-N) encryption salt values
1574             # Returns: encrypted/decrypted value
1575             # Notes:
1576             # 1) The encryption salt starts with '-' to reverse the encryption algorithm
1577             # 2) Additional salt values are provided when tag stores multiple arrays
1578             # (in which case the first value of the tag gives the array length)
1579             sub Crypt($$$@)
1580             {
1581 0     0 0 0 my ($et, $val, $tagInfo, @salt) = @_;
1582 0 0       0 my $key = $$et{EncryptionKey} or return undef;
1583 0 0 0     0 my $format = $$tagInfo{Writable} || $$tagInfo{Format} or return undef;
1584 0 0       0 return undef unless $formatMinMax{$format};
1585 0         0 my ($min, $max) = @{$formatMinMax{$format}};
  0         0  
1586 0         0 my @a = split ' ', $val;
1587 0 0       0 my $newSalt = (@salt > 1) ? 1 : 0; # skip length entry if this is an array
1588 0         0 my ($i, $sign, $salt, $start);
1589 0         0 for ($i=$newSalt; $i<@a; ++$i) {
1590 0 0       0 if ($i == $newSalt) {
1591 0         0 $start = $i;
1592 0         0 $salt = shift @salt;
1593 0 0       0 $sign = ($salt =~ s/^-//) ? -1 : 1;
1594 0 0       0 $newSalt += $a[0] if @salt;
1595             }
1596 0         0 $a[$i] += $sign * $$key[($salt+$i-$start) % scalar(@$key)];
1597             # handle integer wrap-around
1598 0 0       0 if ($sign > 0) {
1599 0 0       0 $a[$i] -= $max - $min + 1 if $a[$i] > $max;
1600             } else {
1601 0 0       0 $a[$i] += $max - $min + 1 if $a[$i] < $min;
1602             }
1603             }
1604 0         0 return "@a";
1605             }
1606              
1607             #------------------------------------------------------------------------------
1608             # Process Samsung MP4 INFO data
1609             # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
1610             # Returns: 1 on success
1611             sub ProcessINFO($$$)
1612             {
1613 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
1614 0         0 my $dataPt = $$dirInfo{DataPt};
1615 0         0 my $pos = $$dirInfo{DirStart};
1616 0         0 my $len = $$dirInfo{DirLen};
1617 0         0 my $end = $pos + $len;
1618 0         0 $et->VerboseDir('INFO', undef, $len);
1619 0         0 while ($pos + 8 <= $end) {
1620 0         0 my $tag = substr($$dataPt, $pos, 4);
1621 0         0 my $val = Get32u($dataPt, $pos + 4);
1622 0 0       0 unless ($$tagTablePtr{$tag}) {
1623 0         0 my $name = "Samsung_INFO_$tag";
1624 0         0 $name =~ tr/-_0-9a-zA-Z//dc;
1625 0 0       0 AddTagToTable($tagTablePtr, $tag, { Name => $name }) if $name;
1626             }
1627 0         0 $et->HandleTag($tagTablePtr, $tag, $val);
1628 0         0 $pos += 8;
1629             }
1630 0         0 return 1;
1631             }
1632              
1633             #------------------------------------------------------------------------------
1634             # Read Samsung Meta Info from trailer
1635             # Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref
1636             # Returns: true on success
1637             sub ProcessSamsungMeta($$$)
1638             {
1639 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
1640 0         0 my $dirName = $$dirInfo{DirName};
1641 0         0 my $dataPt = $$dirInfo{DataPt};
1642 0         0 my $pos = $$dirInfo{DirStart};
1643 0         0 my $end = $$dirInfo{DirLen} + $pos;
1644 0 0 0     0 unless ($pos + 8 <= $end and substr($$dataPt, $pos, 4) eq 'DOFS') {
1645 0         0 $et->Warn("Unrecognized $dirName data", 1);
1646 0         0 return 0;
1647             }
1648 0         0 my $ver = Get32u($dataPt, $pos + 4);
1649 0 0       0 if ($ver == 3) {
1650 0 0 0     0 unless ($pos + 18 <= $end and Get32u($dataPt, $pos + 12) == $$dirInfo{DirLen}) {
1651 0         0 $et->Warn("Unrecognized $dirName version $ver data");
1652 0         0 return 0;
1653             }
1654 0         0 my $num = Get16u($dataPt, $pos + 16);
1655 0         0 $et->VerboseDir("$dirName version $ver", $num);
1656 0         0 $pos += 18;
1657 0         0 my ($i, $val);
1658 0         0 for ($i=0; $i<$num; ++$i) {
1659 0 0       0 last if $pos + 2 > $end;
1660 0         0 my ($x, $n) = unpack("x${pos}CC", $$dataPt);
1661 0         0 $pos += 2;
1662 0 0       0 last if $pos + $n + 2 > $end;
1663 0         0 my $tag = substr($$dataPt, $pos, $n);
1664 0         0 my $len = Get16u($dataPt, $pos + $n);
1665 0         0 $pos += $n + 2;
1666 0 0       0 last if $pos + $len > $end;
1667 0 0       0 if ($len == 4) {
1668 0         0 $val = Get32u($dataPt, $pos);
1669             } else {
1670 0         0 my $tmp = substr($$dataPt, $pos, $len);
1671 0         0 $val = \$pos;
1672             }
1673 0         0 $et->HandleTag($tagTablePtr, $tag, $val);
1674 0         0 $pos += $len;
1675             }
1676 0 0       0 $et->Warn("Unexpected end of $dirName version $ver $i $num data") if $i < $num;
1677             }
1678 0         0 return 1;
1679             }
1680              
1681             #------------------------------------------------------------------------------
1682             # Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref
1683             # Returns: true on success
1684             sub ProcessSamsungIFD($$$)
1685             {
1686 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
1687 0         0 my $len = $$dirInfo{DataLen};
1688 0         0 my $pos = $$dirInfo{DirStart};
1689 0 0       0 return 0 unless $pos + 4 < $len;
1690 0         0 my $dataPt = $$dirInfo{DataPt};
1691 0         0 my $buff = substr($$dataPt, $pos, 4);
1692             # this is not an IFD for many models
1693             # (the string "Park Byeongchan" is often found here)
1694 0 0       0 return 0 unless $buff =~ s/^([^\0])\0\0\0/$1\0$1\0/s;
1695 0         0 my $numEntries = ord $1;
1696 0 0       0 if ($$et{HTML_DUMP}) {
1697 0         0 my $pt = $$dirInfo{DirStart} + $$dirInfo{DataPos} + $$dirInfo{Base};
1698 0         0 $et->HDump($pt-44, 44, "MakerNotes header", 'Samsung');
1699 0         0 $et->HDump($pt, 4, "MakerNotes entries", "Format: int32u\nEntry count: $numEntries");
1700 0         0 $$dirInfo{NoDumpEntryCount} = 1;
1701             }
1702 0         0 substr($$dataPt, $pos, 4) = $buff; # insert bogus 2-byte entry count
1703             # offset base is at end of IFD
1704 0         0 my $shift = $$dirInfo{DirStart} + 4 + $numEntries * 12 + 4;
1705 0         0 $$dirInfo{Base} += $shift;
1706 0         0 $$dirInfo{DataPos} -= $shift;
1707 0         0 $$dirInfo{DirStart} += 2; # start at bogus entry count
1708 0         0 $$dirInfo{ZeroOffsetOK} = 1; # disable check for zero offset
1709 0         0 delete $$et{NO_UNKNOWN}; # (set for BinaryData, but not for EXIF IFD's)
1710 0         0 my $rtn = Image::ExifTool::Exif::ProcessExif($et, $dirInfo, $tagTablePtr);
1711 0         0 substr($$dataPt, $pos + 2, 1) = "\0"; # remove bogus count
1712 0         0 return $rtn;
1713             }
1714              
1715             #------------------------------------------------------------------------------
1716             # Read/write Samsung trailer (ie. "Sound & Shot" written by Galaxy Tab S (SM-T805))
1717             # Inputs: 0) ExifTool object reference, 1) dirInfo reference
1718             # Returns: 1 on success, 0 not valid Samsung trailer, or -1 error writing
1719             # - updates DataPos to point to start of Samsung trailer
1720             # - updates DirLen to existing trailer length
1721             sub ProcessSamsung($$;$)
1722             {
1723 26     26 0 91 my ($et, $dirInfo) = @_;
1724 26         89 my $raf = $$dirInfo{RAF};
1725 26   50     121 my $offset = $$dirInfo{Offset} || 0;
1726 26         68 my $outfile = $$dirInfo{OutFile};
1727 26         161 my $verbose = $et->Options('Verbose');
1728 26         98 my $unknown = $et->Options('Unknown');
1729 26         75 my ($buff, $buf2, $index, $offsetPos, $audioNOff, $audioSize);
1730              
1731 26 50       139 unless ($raf) {
1732 0         0 $raf = File::RandomAccess->new($$dirInfo{DataPt});
1733 0         0 $et->VerboseDir('SamsungTrailer');
1734             }
1735 26 50 33     163 return 0 unless $raf->Seek(-6-$offset, 2) and $raf->Read($buff, 6) == 6 and
      33        
      33        
1736             ($buff eq 'QDIOBS' or $buff eq "\0\0SEFT");
1737 26         101 my $endPos = $raf->Tell();
1738 26 50 50     172 $raf->Seek(-2, 1) or return 0 if $buff eq 'QDIOBS'; # rewind to before 'BS'
1739 26         80 my $blockEnd = $raf->Tell();
1740 26         149 SetByteOrder('II');
1741              
1742             # read blocks backward until we find the SEFH/SEFT block
1743             # (the only other block I have seen is QDIO/QDIO)
1744             SamBlock:
1745 26         58 for (;;) {
1746 52 50 33     198 last unless $raf->Seek($blockEnd-8, 0) and $raf->Read($buff, 8) == 8;
1747 52         178 my $type = substr($buff, 4);
1748 52 50       359 last unless $type =~ /^\w+$/;
1749 52         210 my $len = Get32u(\$buff, 0);
1750 52 50 33     352 last unless $len < 0x10000 and $len >= 4 and $len + 8 < $blockEnd;
      33        
1751 52 50 33     182 last unless $raf->Seek(-8-$len, 1) and $raf->Read($buff, $len) == $len;
1752 52         137 $blockEnd -= $len + 8;
1753 52 100       151 unless ($type eq 'SEFT') { # look for directory block (ends with "SEFT")
1754 26 100 66     143 next unless $outfile and $type eq 'QDIO';
1755             # QDIO block format:
1756             # 0 - 'QDIO'
1757             # 4 - int32u: 101 (version)
1758             # 8 - int32u: 1
1759             # 12 - int32u: absolute offset of audio file start (augh!!)
1760             # 16 - int32u: absolute offset of audio file end (augh!!)
1761             # 20 - int32u: 20 (QDIO block length minus 8)
1762             # 24 - 'QDIO'
1763 7 50       29 if ($len == 20) {
1764             # save position of audio file offset in QDIO block
1765 7         45 $offsetPos = $endPos - $raf->Tell() + $len - 12;
1766             } else {
1767 0         0 $et->Error('Unsupported Samsung trailer QDIO block', 1);
1768             }
1769 7         22 next;
1770             }
1771             # validate SEFH header
1772 26 50 33     342 unless ($buff =~ /^SEFH/ and $len >= 12) {
1773             # tolerate extra junk written by Samsung Gallery
1774 0 0       0 last unless $buff =~ /\0\0SEFT/g;
1775 0         0 $et->Warn('Trailer likely corrupted by Samsung Gallery');
1776 0         0 $blockEnd += pos($buff);
1777 0         0 next;
1778             }
1779 26         97 my $dirPos = $raf->Tell() - $len;
1780             # my $ver = Get32u(\$buff, 0x04); # version (=101)
1781 26         104 my $count = Get32u(\$buff, 0x08);
1782 26 50       104 last if 12 + 12 * $count > $len;
1783 26         125 my $tagTablePtr = GetTagTable('Image::ExifTool::Samsung::Trailer');
1784              
1785             # scan ahead quickly to look for the block where the data comes first
1786             # (have only seen this to be the first in the directory, but just in case)
1787 26         64 my $firstBlock = 0;
1788 26         122 for ($index=0; $index<$count; ++$index) {
1789 52         101 my $entry = 12 + 12 * $index;
1790 52         147 my $noff = Get32u(\$buff, $entry + 4); # negative offset
1791 52 100       232 $firstBlock = $noff if $firstBlock < $noff;
1792             }
1793             # save trailer position and length
1794 26         89 my $dataPos = $$dirInfo{DataPos} = $dirPos - $firstBlock;
1795 26         95 my $dirLen = $$dirInfo{DirLen} = $endPos - $dataPos;
1796 26 0 33     194 if (($verbose or $$et{HTML_DUMP}) and not $outfile and $$dirInfo{RAF}) {
      33        
      33        
1797 0         0 $et->DumpTrailer($dirInfo);
1798 0 0       0 return 1 if $$et{HTML_DUMP};
1799             }
1800             # read through the SEFH/SEFT directory entries
1801 26         108 for ($index=0; $index<$count; ++$index) {
1802 52         124 my $entry = 12 + 12 * $index;
1803             # first 2 bytes always 0 (may be part of block type)
1804 52         184 my $type = Get16u(\$buff, $entry + 2); # block type
1805 52         173 my $noff = Get32u(\$buff, $entry + 4); # negative offset
1806 52         156 my $size = Get32u(\$buff, $entry + 8); # block size
1807 52 50 33     362 last SamBlock if $noff > $dirPos or $size > $noff or $size < 8;
      33        
1808 52 50       176 $firstBlock = $noff if $firstBlock < $noff;
1809 52 100       135 if ($outfile) {
1810 14 100 66     135 next unless $type == 0x0100 and not $audioNOff;
1811             # save offset and length of first audio file for QDIO block
1812 7 50 33     33 last unless $raf->Seek($dirPos-$noff, 0) and $raf->Read($buf2, 8) == 8;
1813 7         30 $len = Get32u(\$buf2, 4);
1814 7         17 $audioNOff = $noff - 8 - $len; # negative offset to start of audio data
1815 7         19 $audioSize = $size - 8 - $len;
1816 7         31 next;
1817             }
1818 38 50 33     160 last unless $raf->Seek($dirPos-$noff, 0) and $raf->Read($buf2, $size) == $size;
1819             # (could validate the first 4 bytes of the block because they
1820             # are the same as the first 4 bytes of the directory entry)
1821 38         138 $len = Get32u(\$buf2, 4);
1822 38 50       121 last if $len + 8 > $size;
1823 38         181 my $tag = sprintf("0x%.4x", $type);
1824             # add unknown tags if necessary
1825 38 100       170 unless ($$tagTablePtr{$tag}) {
1826 17 100 66     142 next unless $unknown or $verbose;
1827 1         11 my %tagInfo = (
1828             Name => "SamsungTrailer_$tag",
1829             Description => "Samsung Trailer $tag",
1830             Unknown => 1,
1831             Binary => 1,
1832             );
1833 1         6 AddTagToTable($tagTablePtr, $tag, \%tagInfo);
1834             }
1835 22 100       111 unless ($$tagTablePtr{"$tag-name"}) {
1836 1         8 my %tagInfo2 = (
1837             Name => "SamsungTrailer_${tag}Name",
1838             Description => "Samsung Trailer $tag Name",
1839             Unknown => 1,
1840             );
1841 1         6 AddTagToTable($tagTablePtr, "$tag-name", \%tagInfo2);
1842             }
1843             # set SamsungTagName ExifTool member for use in tag Condition
1844 22         101 $$et{SamsungTagName} = substr($buf2, 8, $len);
1845             # extract tag name and value
1846 22         187 $et->HandleTag($tagTablePtr, "$tag-name", undef,
1847             DataPt => \$buf2,
1848             DataPos => $dirPos - $noff,
1849             Start => 8,
1850             Size => $len,
1851             );
1852 22         164 $et->HandleTag($tagTablePtr, $tag, undef,
1853             DataPt => \$buf2,
1854             DataPos => $dirPos - $noff,
1855             Start => 8 + $len,
1856             Size => $size - (8 + $len),
1857             );
1858 22         105 delete $$et{SamsungTagName};
1859             }
1860 26 100       86 if ($outfile) {
1861 7 50 33     29 last unless $raf->Seek($dataPos, 0) and $raf->Read($buff, $dirLen) == $dirLen;
1862             # adjust the absolute offset in the QDIO block if necessary
1863 7 50 33     51 if ($offsetPos and $audioNOff) {
1864             # initialize the audio file start/end position in the QDIO block
1865 7         59 my $newPos = Tell($outfile) + $dirPos - $audioNOff - $dataPos;
1866 7         61 Set32u($newPos, \$buff, length($buff) - $offsetPos);
1867 7         37 Set32u($newPos + $audioSize, \$buff, length($buff) - $offsetPos + 4);
1868             # add a fixup so the calling routine can apply further shifts if necessary
1869 7         59 require Image::ExifTool::Fixup;
1870 7         25 my $fixup = $$dirInfo{Fixup};
1871 7 50       90 $fixup or $fixup = $$dirInfo{Fixup} = Image::ExifTool::Fixup->new;
1872 7         42 $fixup->AddFixup(length($buff) - $offsetPos);
1873 7         65 $fixup->AddFixup(length($buff) - $offsetPos + 4);
1874             }
1875 7 50       25 $et->VPrint(0, " Writing Samsung trailer ($dirLen bytes)\n") if $verbose;
1876 7 50       42 Write($$dirInfo{OutFile}, $buff) or return -1;
1877 7         38 return 1;
1878             }
1879 19         82 return 1;
1880             }
1881 0         0 $et->Warn('Error processing Samsung trailer',1);
1882 0         0 return 0;
1883             }
1884              
1885             #------------------------------------------------------------------------------
1886             # Write Samsung STMN maker notes
1887             # Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref
1888             # Returns: Binary data block or undefined on error
1889             sub WriteSTMN($$$)
1890             {
1891 76     76 0 237 my ($et, $dirInfo, $tagTablePtr) = @_;
1892             # create a Fixup for the PreviewImage
1893 76         758 $$dirInfo{Fixup} = Image::ExifTool::Fixup->new;
1894 76         375 my $val = Image::ExifTool::WriteBinaryData($et, $dirInfo, $tagTablePtr);
1895             # force PreviewImage into the trailer even if it fits in EXIF segment
1896 76 50       323 $$et{PREVIEW_INFO}{IsTrailer} = 1 if $$et{PREVIEW_INFO};
1897 76         473 return $val;
1898             }
1899              
1900             1; # end
1901              
1902             __END__