Example #1
0
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
Example #2
0
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
Example #3
0
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
Example #4
0
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