def target_data(target_types=None, external_targets=None, performance_data=None, child_elements=None): """ Returns MIX TargetData element. :target_types: The target types as a list (or string) :external_targets: The locations of external targets as a list :performance_data: The location of performance data as a string :child_elements: Child elements as a list Returns the following ElementTree structure:: <mix:TargetData> <mix:targetType>internal</mix:targetType> <mix:TargetID/> <mix:externalTarget>http://foo</mix:externalTarget> <mix:performanceData>http://foo</mix:performanceData> </mix:TargetData> """ container = _element('TargetData') if child_elements is None: child_elements = [] if target_types: target_types = _ensure_list(target_types) for item in target_types: if item in TARGET_TYPES: type_el = _element('targetType') type_el.text = item child_elements.append(type_el) else: raise RestrictedElementError(item, 'targetType', TARGET_TYPES) if external_targets: external_targets = _ensure_list(external_targets) for item in external_targets: target_el = _element('externalTarget') target_el.text = item child_elements.append(target_el) if performance_data: performance_data = _ensure_list(performance_data) for item in performance_data: data_el = _element('performanceData') data_el.text = item child_elements.append(data_el) child_elements.sort(key=target_data_order) for element in child_elements: container.append(element) return container
def bits_per_sample(sample_values=None, sample_unit=None): """ Returns the MIX BitsPerSample element. :sample_values: The bits per sample values as a list :sample_unit: The bits per sample unit as a string Returns the following ElementTree structure:: <mix:BitsPerSample> <mix:bitsPerSampleValue>8</mix:bitsPerSampleValue> <mix:bitsPerSampleUnit>integer</mix:bitsPerSampleUnit> </mix:BitsPerSample> """ container = _element('BitsPerSample') if sample_values: sample_values = _ensure_list(sample_values) for item in sample_values: value_el = _subelement(container, 'bitsPerSampleValue') value_el.text = six.text_type(item) if sample_unit: if sample_unit in BITS_PER_SAMPLE_UNITS: unit_el = _subelement(container, 'bitsPerSampleUnit') unit_el.text = sample_unit else: raise RestrictedElementError(sample_unit, 'bitsPerSampleUnit', BITS_PER_SAMPLE_UNITS) return container
def gray_response(curves=None, unit=None): """ Returns the MIX GrayResponse element. :curves: The optical density of pixels as a list (of integers) :unit: The precision recorded in grayResponseCurve Returns the following ElementTree structure:: <mix:GrayResponse> <mix:grayResponseCurve>10</mix:grayResponseCurve> <mix:grayResponseUnit> Number represents tenths of a unit </mix:grayResponseUnit> </mix:GrayResponse> """ container = _element('GrayResponse') if curves: curves = _ensure_list(curves) for item in curves: curve_el = _subelement(container, 'grayResponseCurve') curve_el.text = six.text_type(item) if unit: if unit in GRAY_RESPONSE_UNITS: unit_el = _subelement(container, 'grayResponseUnit') unit_el.text = unit else: raise RestrictedElementError(unit, 'grayResponseUnit', GRAY_RESPONSE_UNITS) return container
def color_encoding(samples_pixel=None, extra_samples=None, child_elements=None): """ Returns the MIX ImageColorEncoding element. :samples_pixel: The number of samples per pixel as an integer :extra_samples: The types of extra samples as a list :child_elements: Child elements as a list Returns the following sorted ElementTree structure:: <mix:ImageColorEncoding> <mix:BitsPerSample/> <mix:samplesPerPixel>3</mix:samplesPerPixel> <mix:extraSamples>unspecified data</mix:extraSamples> <mix:Colormap/> <mix:GrayResponse/> <mix:WhitePoint/> <mix:PrimaryChromaticities/> </mix:ImageColorEncoding> """ container = _element('ImageColorEncoding') if child_elements is None: child_elements = [] if samples_pixel: pixel_el = _element('samplesPerPixel') pixel_el.text = six.text_type(samples_pixel) child_elements.append(pixel_el) if extra_samples: extra_samples = _ensure_list(extra_samples) for item in extra_samples: if item in EXTRA_SAMPLES_TYPES: samples_el = _element('extraSamples') samples_el.text = item child_elements.append(samples_el) else: raise RestrictedElementError(item, 'extraSamples', EXTRA_SAMPLES_TYPES) child_elements.sort(key=color_encoding_order) for element in child_elements: container.append(element) return container
def capture_information(created=None, producer=None, device=None): """ Returns the MIX GeneralCaptureInformation element. :created: The image datetime created as a string :producer: The image producer as a string :device: The image creation device classification as a string Returns the following sorted ElementTree structure:: <mix:GeneralCaptureInformation> <mix:dateTimeCreated>foo</mix:dateTimeCreated> <mix:imageProducer>foo</mix:imageProducer> <mix:captureDevice>foo</mix:captureDevice> </mix:GeneralCaptureInformation> """ container = _element('GeneralCaptureInformation') if created: created_el = _subelement(container, 'dateTimeCreated') created_el.text = created if producer: producer = _ensure_list(producer) for item in producer: producer_el = _subelement(container, 'imageProducer') producer_el.text = item if device: if device in CAPTURE_DEVICE_TYPES: device_el = _subelement(container, 'captureDevice') device_el.text = device else: raise RestrictedElementError(device, 'captureDevice', CAPTURE_DEVICE_TYPES) return container
def test_ensure_list(value, length): """Tests the _ensure_list function.""" list_value = _ensure_list(value) assert isinstance(list_value, list) assert len(list_value) == length
def image_processing(datetime=None, source_data=None, agencies=None, rationale=None, actions=None, child_elements=None): """ Returns the MIX ImageProcessing element. :datetime: The image processing datetime as a string :source_data: The location of source image data as a string :agencies: The processing agencies as a list (or string) :rationale: The rationale for image processing as a string :actions: The image processing steps as a list :child_elements: Child elements as a list Returns the following ElementTree structure:: <mix:ImageProcessing> <mix:dateTimeProcessed>2019</mix:dateTimeProcessed> <mix:sourceData>foo</mix:sourceData> <mix:processingAgency>acme</mix:processingAgency> <mix:processingRationale>test</mix:processingRationale> <mix:ProcessingSoftware>mysoftware</mix:ProcessingSoftware> <mix:processingActions>rotate</mix:processingActions> </mix:ImageProcessing> """ container = _element('ImageProcessing') if child_elements is None: child_elements = [] if datetime: datetime_el = _element('dateTimeProcessed') datetime_el.text = datetime child_elements.append(datetime_el) if source_data: source_data_el = _element('sourceData') source_data_el.text = source_data child_elements.append(source_data_el) if agencies: agencies = _ensure_list(agencies) for item in agencies: agency_el = _element('processingAgency') agency_el.text = item child_elements.append(agency_el) if rationale: rationale_el = _element('processingRationale') rationale_el.text = rationale child_elements.append(rationale_el) if actions: actions = _ensure_list(actions) for item in actions: action_el = _element('processingActions') action_el.text = item child_elements.append(action_el) child_elements.sort(key=image_processing_order) for element in child_elements: container.append(element) return container
def image_data(contents=None): """ Returns the MIX ImageData element. The function argument contents is a dict, that can be retrieved from nisomix.IMAGE_DATA_CONTENTS. The keys from contents are matched to create the MIX element and its substructure. The dict should look like this:: contents = {"fnumber": None, "exposure_time": None, "exposure_program": None, "spectral_sensitivity": None, "isospeed_ratings": None, "oecf": None, "exif_version": None, "shutter_speed_value": None, "aperture_value": None, "brightness_value": None, "exposure_bias_value": None, "max_aperture_value": None, "distance": None, "min_distance": None, "max_distance": None, "metering_mode": None, "light_source": None, "flash": None, "focal_length": None, "flash_energy": None, "back_light": None, "exposure_index": None, "sensing_method": None, "cfa_pattern": None, "auto_focus": None, "x_print_aspect_ratio": None, "y_print_aspect_ratio": None} """ tags = { 'fnumber': 'fNumber', 'exposure_time': 'exposureTime', 'exposure_program': 'exposureProgram', 'isospeed_ratings': 'isoSpeedRatings', 'exif_version': 'exifVersion', 'metering_mode': 'meteringMode', 'light_source': 'lightSource', 'flash': 'flash', 'focal_length': 'focalLength', 'back_light': 'backLight', 'exposure_index': 'exposureIndex', 'sensing_method': 'sensingMethod', 'cfa_pattern': 'cfaPattern', 'auto_focus': 'autoFocus' } rationals = { 'oecf': 'oECF', 'shutter_speed_value': 'shutterSpeedValue', 'aperture_value': 'apertureValue', 'brightness_value': 'brightnessValue', 'exposure_bias_value': 'exposureBiasValue', 'max_aperture_value': 'maxApertureValue', 'flash_energy': 'flashEnergy' } for key in contents: if key not in IMAGE_DATA_CONTENTS: raise ValueError('Key "%s" not in supported keys for ' 'image_data.' % key) container = _element('ImageData') child_elements = [] for key, value in six.iteritems(contents): if key in tags and value: elem = _element(tags[key]) elem.text = six.text_type(value) child_elements.append(elem) if key in rationals and value: elem = _rationaltype_element(rationals[key], value) child_elements.append(elem) if contents.get("spectral_sensitivity"): spect_sens = _ensure_list(contents["spectral_sensitivity"]) for item in spect_sens: spect_sens_el = _element('spectralSensitivity') spect_sens_el.text = item child_elements.append(spect_sens_el) if contents.get("distance") or contents.get("min_distance") \ or contents.get("max_distance"): subject_distance = _element('SubjectDistance') child_elements.append(subject_distance) if contents.get("distance"): distance_el = _subelement(subject_distance, 'distance') distance_el.text = contents["distance"] if contents.get("min_distance") or contents.get("max_distance"): min_max_distance = _subelement(subject_distance, 'MinMaxDistance') if contents.get("min_distance"): min_distance_el = _subelement(min_max_distance, 'minDistance') min_distance_el.text = contents["min_distance"] if contents.get("max_distance"): max_distance_el = _subelement(min_max_distance, 'maxDistance') max_distance_el.text = contents["max_distance"] if contents.get("x_print_aspect_ratio") or \ contents.get("y_print_aspect_ratio"): print_ratio = _element('PrintAspectRatio') child_elements.append(print_ratio) if contents.get("x_print_aspect_ratio"): x_print_aspect_ratio_el = _subelement(print_ratio, 'xPrintAspectRatio') x_print_aspect_ratio_el.text = contents["x_print_aspect_ratio"] if contents.get("y_print_aspect_ratio"): y_print_aspect_ratio_el = _subelement(print_ratio, 'yPrintAspectRatio') y_print_aspect_ratio_el.text = contents["y_print_aspect_ratio"] child_elements.sort(key=image_data_order) for element in child_elements: container.append(element) return container