28from __future__
import print_function
31import xml.etree.ElementTree
as ET
36 print(*args, file=sys.stderr, **kwargs)
39 sys.exit(
"Usage: extract_wb <file1> [file2] ...")
41IGNORED_PRESETS = {
"Auto",
"Kelvin",
"Measured",
"AsShot",
"As Shot",
"Preset",
42 "Natural Auto",
"Multi Auto",
"Color Temperature Enhancement",
43 "One Touch WB 1",
"One Touch WB 2",
"One Touch WB 3",
44 "One Touch WB 4",
"Custom WB 1",
"Auto0",
"Auto1",
"Auto2",
45 "Custom",
"CWB1",
"CWB2",
"CWB3",
"CWB4",
"Black",
46 "Illuminator1",
"Illuminator2",
"Uncorrected"}
49 "Fluorescent" :
"CoolWhiteFluorescent",
50 "FluorescentP1" :
"DayWhiteFluorescent",
51 "FluorescentP2" :
"DaylightFluorescent",
52 "FluorescentM1" :
"WarmWhiteFluorescent",
53 "FluorescentD" :
"DaylightFluorescent",
54 "FluorescentN" :
"NeutralFluorescent",
55 "FluorescentW" :
"WhiteFluorescent",
56 "Daylight Fluorescent" :
"DaylightFluorescent",
57 "Day White Fluorescent" :
"DayWhiteFluorescent",
58 "White Fluorescent" :
"WhiteFluorescent",
59 "Unknown (0x600)" :
"Underwater",
60 "Sunny" :
"DirectSunlight",
61 "Fine Weather" :
"DirectSunlight",
62 "Tungsten (Incandescent)" :
"Tungsten",
63 "ISO Studio Tungsten" :
"Tungsten",
64 "Cool WHT FL" :
"CoolWhiteFluorescent",
65 "Daylight FL" :
"DaylightFluorescent",
66 "Warm WHT FL" :
"WarmWhiteFluorescent",
67 "Warm White Fluorescent" :
"WarmWhiteFluorescent",
68 "White FL" :
"WhiteFluorescent",
69 "Mercury Lamp" :
"HighTempMercuryVaporFluorescent",
70 "Day White FL" :
"DayWhiteFluorescent",
71 "Sodium Lamp" :
"SodiumVaporFluorescent",
72 "3000K (Tungsten light)" :
"Tungsten",
73 "4000K (Cool white fluorescent)" :
"CoolWhiteFluorescent",
74 "5300K (Fine Weather)" :
"Daylight",
75 "5500K (Flash)" :
"Flash",
76 "6000K (Cloudy)" :
"Cloudy",
77 "7500K (Fine Weather with Shade)" :
"Shade",
80PRESET_ORDER = [
"DirectSunlight",
"Daylight",
"D55",
"Shade",
"Cloudy",
81 "Tungsten",
"Incandescent",
"Fluorescent",
82 "WarmWhiteFluorescent",
"CoolWhiteFluorescent",
83 "DayWhiteFluorescent",
"DaylightFluorescent",
84 "DaylightFluorescent",
"NeutralFluorescent",
"WhiteFluorescent",
85 "HighTempMercuryVaporFluorescent",
"HTMercury",
86 "SodiumVaporFluorescent",
"Underwater",
"Flash",
"Unknown"]
88PRESET_SORT_MAPPING = {}
90for index,name
in enumerate(PRESET_ORDER):
91 PRESET_SORT_MAPPING[name] = index + 1
93cams_from_source = os.path.dirname(os.path.abspath(__file__)) +
"/../src/external/rawspeed/data/cameras.xml"
94cams_from_dist = os.path.dirname(os.path.abspath(__file__)) +
"/../rawspeed/cameras.xml"
96CAMERAS = os.path.abspath(cams_from_source)
if os.path.exists(os.path.abspath(cams_from_source))
else os.path.abspath(cams_from_dist)
98if not os.path.exists(CAMERAS):
99 sys.exit(
"Can't find cameras mapping file, should be in {0}".format(CAMERAS))
102xml_doc = ET.parse(CAMERAS)
103for camera
in xml_doc.getroot().findall(
'Camera'):
104 maker = exif_maker = camera.get(
'make')
105 model = exif_model = camera.get(
'model')
106 exif_id = maker,model
107 if camera.find(
'ID')
is not None:
108 cid = camera.find(
'ID')
109 maker = cid.get(
'make')
110 model = cid.get(
'model')
111 exif_name_map[exif_id] = maker,model
112 for alias
in camera.findall(
'Aliases/Alias'):
113 exif_model = alias.text
114 exif_id = exif_maker, exif_model
115 exif_name_map[exif_id] = maker,model
119for filename
in sys.argv[1:]:
120 red = green = blue = maker = model = preset =
None
121 finetune = fl_count = rlevel = blevel = glevel = 0
125 command =
"exiftool -Make -Model \"-WBType*\" \"-WB_*\" \"-ColorTemp*\" "\
126 "-WhiteBalance -WhiteBalance2 -WhitePoint -ColorCompensationFilter "\
127 "-WBShiftAB -WBShiftAB_GM -WBShiftAB_GM_Precise -WBShiftGM -WBScale "\
128 "-WhiteBalanceFineTune -WhiteBalanceComp -WhiteBalanceSetting "\
129 "-WhiteBalanceBracket -WhiteBalanceBias -WBMode -WhiteBalanceMode "\
130 "-WhiteBalanceTemperature -WhiteBalanceDetected -ColorTemperature "\
131 "-WBShiftIntelligentAuto -WBShiftCreativeControl -WhiteBalanceSetup "\
132 "-WBRedLevel -WBBlueLevel -WBGreenLevel -RedBalance -BlueBalance "\
133 "\"{0}\"".format(filename)
134 if filename.endswith((
'.txt',
'.TXT')):
135 command =
'cat "{0}"'.format(filename)
136 command = shlex.split(command)
137 proc = subprocess.check_output(command, universal_newlines=
True)
138 for io
in proc.splitlines():
139 lineparts = io.split(
':')
140 tag = lineparts[0].strip()
141 values = lineparts[1].strip().split(
' ')
142 if 'Make' in tag.split():
143 maker = lineparts[1].strip()
144 elif 'Model' in tag.split():
145 model = lineparts[1].strip()
146 elif tag ==
"WB RGGB Levels":
147 green = (float(values[1])+float(values[2]))/2.0
148 red = float(values[0])/green
149 blue = float(values[3])/green
151 elif tag ==
"WB RB Levels":
152 red = float(values[0])
153 blue = float(values[1])
154 if len(values) == 4
and values[2] ==
"256" and values[3] ==
"256":
158 elif tag ==
"WB GRB Levels":
159 green = float(values[0])
160 red = float(values[1])/green
161 blue = float(values[2])/green
168 elif tag ==
"White Point" and len(values) > 3:
169 green = (float(values[1])+float(values[2]))/2.0
170 red = float(values[0])/green
171 blue = float(values[3])/green
173 elif tag ==
"White Balance" or tag ==
"White Balance 2":
174 preset =
' '.join(values)
175 if preset
in FL_PRESET_REPLACE:
176 preset = FL_PRESET_REPLACE[preset]
177 elif ' '.join(tag.split()[:2]) ==
"WB Type":
178 preset_names[
' '.join(tag.split()[2:])] =
' '.join(values)
179 elif ' '.join(tag.split()[:3])
in [
'WB RGB Levels',
'WB RGGB Levels',
'WB RB Levels']:
181 p =
''.join(tag.split()[3:])
182 if( p
in preset_names):
187 if len(values) == 4
and ' '.join(tag.split()[:3])
in [
'WB RB Levels']:
188 g = (float(values[2])+float(values[3]))/2.0
189 r = float(values[0])/g
190 b = float(values[1])/g
192 elif len(values) == 4:
193 g = (float(values[1])+float(values[2]))/2.0
194 r = float(values[0])/g
195 b = float(values[3])/g
197 elif len(values) == 3:
199 r = float(values[0])/g
200 b = float(values[2])/g
202 elif len(values) == 2
and ' '.join(tag.split()[:3])
in [
'WB RB Levels']:
207 eprint(
"Found RGB tag '{0}' with {1} values instead of 2, 3 or 4".format(p, len(values)))
209 if 'Fluorescent' in p:
214 if p
not in IGNORED_PRESETS:
215 listed_presets.append(tuple([p,r,g,b]))
216 elif tag ==
"WB Red Level":
217 rlevel = float(values[0])
218 elif tag ==
"WB Blue Level":
219 blevel = float(values[0])
220 elif tag ==
"WB Green Level":
221 glevel = float(values[0])
222 elif tag ==
"WB Shift AB":
224 elif tag ==
"WB Shift GM":
225 gm_skew = gm_skew
or (int(values[0]) != 0)
226 elif tag ==
"WB Shift AB GM":
228 gm_skew = gm_skew
or (int(values[1]) != 0)
229 elif tag ==
"WB Shift AB GM Precise" and maker.startswith(
"SONY"):
230 finetune = int(float(values[0]) * 2.0)
231 gm_skew = gm_skew
or (float(values[1]) != 0.0)
232 elif tag ==
"White Balance Fine Tune" and maker.startswith(
"NIKON"):
233 finetune = 0-(int(values[0]) * 2)
234 gm_skew = gm_skew
or (int(values[1]) != 0)
235 elif tag ==
"White Balance Fine Tune" and maker ==
"FUJIFILM" and int(values[3]) != 0:
236 eprint(
"Warning: Fuji does not seem to produce any sensible data for finetuning! If all finetuned values are identical, use one with no finetuning (0)")
237 finetune = int(values[3]) / 20
238 gm_skew = gm_skew
or (int(values[1].replace(
',',
'')) != 0)
239 elif tag ==
"White Balance Fine Tune" and maker ==
"SONY" and preset ==
"CoolWhiteFluorescent":
241 if values[0] ==
"-1":
242 preset =
"WarmWhiteFluorescent"
243 elif values[0] ==
"0":
244 preset =
"CoolWhiteFluorescent"
245 elif values[0] ==
"1":
246 preset =
"DayWhiteFluorescent"
247 elif values[0] ==
"2":
248 preset =
"DaylightFluorescent"
250 eprint(
"Warning: Unknown Sony Fluorescent WB Preset!")
251 elif tag ==
"White Balance Bracket":
253 gm_skew = gm_skew
or (int(values[1]) != 0)
254 elif tag ==
"Color Compensation Filter":
255 gm_skew = gm_skew
or (int(values[0]) != 0)
257 if rlevel > 0
and glevel > 0
and blevel > 0:
263 eprint(
'WARNING: {0} has finetuning over GM axis! Data is skewed!'.format(filename))
266 if exif_name_map[maker,model]:
267 enm = exif_name_map[maker,model]
271 eprint(
"WARNING: Couldn't find model in cameras.xml ('{0}', '{1}')".format(maker, model))
273 for preset_arr
in listed_presets:
275 preset_arrv = list(preset_arr)
276 if maker
and maker ==
"Canon" and preset_arrv[0] ==
"Fluorescent":
277 preset_arrv[0] =
"WhiteFluorescent"
278 if preset_arrv[0]
in FL_PRESET_REPLACE:
279 preset_arrv[0] = FL_PRESET_REPLACE[preset_arrv[0]]
280 if preset_arrv[0]
not in IGNORED_PRESETS:
281 found_presets.append(tuple([maker,model,preset_arrv[0], 0, preset_arrv[1], preset_arrv[2], preset_arrv[3]]))
286 if red
and green
and blue
and preset
not in IGNORED_PRESETS:
287 found_presets.append(tuple([maker, model, preset, int(finetune), red, green, blue]))
291found_presets = list(set(found_presets))
295 if preset[2]
in IGNORED_PRESETS:
297 elif preset[2]
in PRESET_SORT_MAPPING:
298 sort_for_preset = PRESET_SORT_MAPPING[preset[2]]
299 elif preset[2].endswith(
'K'):
300 sort_for_preset = int(preset[2][:-1])
302 eprint(
"WARNING: no defined sort order for '{0}'".format(preset[2]))
303 return tuple([preset[0], preset[1], sort_for_preset, preset[3], preset[4], preset[5], preset[6]])
305found_presets.sort(key=preset_to_sort)
308for preset
in found_presets:
309 if len(preset[2]) > min_padding:
310 min_padding = len(preset[2])
313for index
in range(len(found_presets)-1):
314 if (found_presets[index][0] ==
'Nikon' and
315 found_presets[index+1][0] == found_presets[index][0]
and
316 found_presets[index+1][1] == found_presets[index][1]
and
317 found_presets[index+1][2] == found_presets[index][2]
and
318 found_presets[index+1][3] == found_presets[index][3]) :
320 curr_finetune = int(found_presets[index][3])
322 if curr_finetune < 0:
323 found_presets[index+1] = list(found_presets[index+1])
324 found_presets[index+1][3] = (int(found_presets[index+1][3]) + 1)
325 found_presets[index+1] = tuple(found_presets[index+1])
326 elif curr_finetune > 0:
327 found_presets[index] = list(found_presets[index])
328 found_presets[index][3] = (curr_finetune) - 1
329 found_presets[index] = tuple(found_presets[index])
332for index
in range(len(found_presets)-1):
333 if ( (found_presets[index][0] ==
"Nikon" or found_presets[index][0] ==
"Sony")
and
334 found_presets[index+1][0] == found_presets[index][0]
and
335 found_presets[index+1][1] == found_presets[index][1]
and
336 found_presets[index+1][2] == found_presets[index][2]) :
338 found_presets[index] = list(found_presets[index])
339 found_presets[index+1] = list(found_presets[index+1])
341 if (found_presets[index+1][3] % 2 == 0
and
342 found_presets[index][3] % 2 == 0
and
343 found_presets[index+1][3] == found_presets[index][3] + 2):
346 found_presets[index][3] = int(found_presets[index][3] / 2)
347 found_presets[index+1][3] = int(found_presets[index+1][3] / 2)
348 elif (found_presets[index+1][3] % 2 == 0
and
349 found_presets[index][3] % 2 == 1
and
350 found_presets[index+1][3] == (found_presets[index][3] + 1)*2
and
351 (index + 2 == len(found_presets)
or
352 found_presets[index+2][2] != found_presets[index+1][2] ) ):
355 found_presets[index+1][3] = int(found_presets[index+1][3] / 2)
357 found_presets[index] = tuple(found_presets[index])
358 found_presets[index+1] = tuple(found_presets[index+1])
362for index
in range(len(found_presets)-1):
363 if (found_presets[index+1][0] == found_presets[index][0]
and
364 found_presets[index+1][1] == found_presets[index][1]
and
365 found_presets[index+1][2] == found_presets[index][2]
and
366 found_presets[index+1][3] != ((found_presets[index][3])+1) ):
369 lazy_finetuning.append(tuple([found_presets[index][0], found_presets[index][1], found_presets[index][2]]))
372lazy_finetuning = list(set(lazy_finetuning))
376for lazy
in lazy_finetuning:
377 eprint(
"Gaps detected in finetuning for {0} {1} preset {2}, dt will need to interpolate!".format(lazy[0], lazy[1], lazy[2]))
379for preset
in found_presets:
380 if preset[2]
in IGNORED_PRESETS:
381 eprint(
"Ignoring preset '{0}'".format(preset[2]))
384 if preset[2].endswith(
'K'):
385 preset_name =
'"'+preset[2]+
'"'
387 preset_name = preset[2]
388 print(
' {{ "{0}", "{1}", {2:<{min_pad}}, {3}, {{ {4}, {5}, {6}, 0 }} }},'.format(preset[0], preset[1], preset_name, preset[3], preset[4], preset[5], preset[6], min_pad=min_padding))