Ejemplo n.º 1
0
def white_point(x_value=None, y_value=None):
    """
    Returns the MIX WhitePoint element.

    :x_value: The X value of white point chromaticity as a list
    :y_value: The Y value of white point chromaticity as a list

    Returns the following ElementTree structure::

        <mix:WhitePoint>
          <mix:whitePointXValue>
            <mix:numerator>10</mix:numerator>
            <mix:denominator>1</mix:denominator>
          </mix:whitePointXValue>
          <mix:whitePointYValue>
            <mix:numerator>10</mix:numerator>
            <mix:denominator>1</mix:denominator>
          </mix:whitePointYValue>
        </mix:WhitePoint>

    """
    container = _element('WhitePoint')

    if x_value:
        _rationaltype_element('whitePointXValue', x_value, parent=container)

    if y_value:
        _rationaltype_element('whitePointYValue', y_value, parent=container)

    return container
Ejemplo n.º 2
0
def spatial_metrics(plane=None, unit=None, x_sampling=None, y_sampling=None):
    """
    Returns the MIX SpatialMetrics element.

    :plane: The sampling frequency plane as a string
    :unit: The sampling frequency unit as a string
    :x_sampling: The y sampling frequency as a list (or integer)
    :y_sampling: The x sampling frequency as a list (or integer)

    Returns the following ElementTree structure::

        <mix:SpatialMetrics>
          <mix:samplingFrequencyPlane>
            object plane
          </mix:samplingFrequencyPlane>
          <mix:samplingFrequencyUnit>cm</mix:samplingFrequencyUnit>
          <mix:xSamplingFrequency>
            <mix:numerator>10</mix:numerator>
            <mix:denominator>1</mix:denominator>
          </mix:xSamplingFrequency>
          <mix:ySamplingFrequency>
            <mix:numerator>10</mix:numerator>
            <mix:denominator>1</mix:denominator>
          </mix:ySamplingFrequency>
        </mix:SpatialMetrics>

    """
    container = _element('SpatialMetrics')

    if plane:
        plane_el = _subelement(container, 'samplingFrequencyPlane')
        if plane in SAMPLING_FREQUENCY_PLANES:
            plane_el.text = plane
        else:
            raise RestrictedElementError(plane, 'samplingFrequencyPlane',
                                         SAMPLING_FREQUENCY_PLANES)

    if unit:
        unit_el = _subelement(container, 'samplingFrequencyUnit')
        if unit in SAMPLING_FREQUENCY_UNITS:
            unit_el.text = unit
        else:
            raise RestrictedElementError(unit, 'samplingFrequencyUnit',
                                         SAMPLING_FREQUENCY_UNITS)

    if x_sampling:
        _rationaltype_element('xSamplingFrequency',
                              x_sampling,
                              parent=container)

    if y_sampling:
        _rationaltype_element('ySamplingFrequency',
                              y_sampling,
                              parent=container)

    return container
Ejemplo n.º 3
0
def compression(compression_scheme=None,
                local_list=None,
                local_value=None,
                compression_ratio=None):
    """
    Returns the MIX Compression element.

    :compression_scheme: The compression scheme as a string
    :local_list: The location of the local enumerated list of
                 compression schemes as a string
    :local_value: The local compression scheme as a string
    :compression_ratio: The compression ratio as a list (or integer)

    Returns the following ElementTree structure::

        <mix:Compression>
            <mix:compressionScheme>
                JPEG 2000 Lossless
            </mix:compressionScheme>
            <mix:compressionSchemeLocalList>
            </mix:compressionSchemeLocalList>
            <mix:compressionSchemeLocalValue>
            </mix:compressionSchemeLocalValue>
            <mix:compressionRatio>
                <mix:numerator>10</mix:numerator>
                <mix:denominator>1</mix:denominator>
            </mix:compressionRatio>
        </mix:Compression>

    """
    container = _element('Compression')

    if compression_scheme:
        compression_scheme_el = _subelement(container, 'compressionScheme')
        compression_scheme_el.text = compression_scheme

    if compression_scheme == 'enumerated in local list':
        local_list_el = _subelement(container, 'compressionSchemeLocalList')
        local_list_el.text = local_list
        local_value_el = _subelement(container, 'compressionSchemeLocalValue')
        local_value_el.text = local_value

    if compression_ratio:
        _rationaltype_element('compressionRatio',
                              compression_ratio,
                              parent=container)

    return container
Ejemplo n.º 4
0
def component(c_photometric_interpretation=None, footroom=None, headroom=None):
    """
    Returns MIX Component element.

    :c_photometric_interpretation: The component photometric
                                   interpretation type as a string
    :footroom: The footroom as a list (or integer)
    :headroom: The headroom as a list (or integer)

    Returns the following ElementTree structure::

        <mix:Component>
          <mix:componentPhotometricInterpretation>
            R
          </mix:componentPhotometricInterpretation>
          <mix:footroom>
            <mix:numerator>10</mix:numerator>
            <mix:denominator>1</mix:denominator>
          </mix:footroom>
          <mix:headroom>
            <mix:numerator>20</mix:numerator>
            <mix:denominator>1</mix:denominator>
          </mix:headroom>
        </mix:Component>

    """
    container = _element('Component')

    if c_photometric_interpretation:
        if c_photometric_interpretation in COMPONENT_INTERPRETATION_TYPES:
            cpi_el = _subelement(container,
                                 'componentPhotometricInterpretation')
            cpi_el.text = c_photometric_interpretation
        else:
            raise RestrictedElementError(c_photometric_interpretation,
                                         'componentPhotometricInterpretation',
                                         COMPONENT_INTERPRETATION_TYPES)

    if footroom:
        _rationaltype_element('footroom', footroom, parent=container)

    if headroom:
        _rationaltype_element('headroom', headroom, parent=container)

    return container
def test_rationaltype_element():
    """
    Tests the _rationaltype_element function by asserting that the
    element was created correctly, that it is containing both the
    numerator and denominator subelements even though the numerator
    sometimes is missing or is None. Also assert that the rational
    element is a subelement of its parent element if parent argument is
    given.
    """
    elem1 = _rationaltype_element('test', 30)

    assert ET.tostring(elem1) == ET.tostring(ET.fromstring(
        '<mix:test xmlns:mix="http://www.loc.gov/mix/v20">'
        '<mix:numerator>30</mix:numerator>'
        '<mix:denominator>1</mix:denominator></mix:test>'))

    elem2 = _rationaltype_element('test', [30, 3])

    assert ET.tostring(elem2) == ET.tostring(ET.fromstring(
        '<mix:test xmlns:mix="http://www.loc.gov/mix/v20">'
        '<mix:numerator>30</mix:numerator>'
        '<mix:denominator>3</mix:denominator></mix:test>'))

    elem3 = _rationaltype_element('test', [30, None])

    assert ET.tostring(elem3) == ET.tostring(ET.fromstring(
        '<mix:test xmlns:mix="http://www.loc.gov/mix/v20">'
        '<mix:numerator>30</mix:numerator>'
        '<mix:denominator>1</mix:denominator></mix:test>'))

    elem4 = _rationaltype_element('test', [30, ''])

    assert ET.tostring(elem4) == ET.tostring(ET.fromstring(
        '<mix:test xmlns:mix="http://www.loc.gov/mix/v20">'
        '<mix:numerator>30</mix:numerator>'
        '<mix:denominator>1</mix:denominator></mix:test>'))

    parent = _element('parent')
    elem5 = _rationaltype_element('test', [30], parent=parent)

    assert ET.tostring(elem5) == ET.tostring(ET.fromstring(
        '<mix:test xmlns:mix="http://www.loc.gov/mix/v20">'
        '<mix:numerator>30</mix:numerator>'
        '<mix:denominator>1</mix:denominator></mix:test>'))
    assert elem5.getparent().tag == '{http://www.loc.gov/mix/v20}parent'
def _gps_group(tag, degrees=None, minutes=None, seconds=None):
    """
    Returns the MIX gpsGroup type element.

    :tag: the tag name of the container element
    :degrees: The degrees of the coordinates as a list (or integer)
    :minutes: The minutes of the coordinates as a list (or integer)
    :seconds: The seconds of the coordinates as a list (or integer)

    Returns the following ElementTree structure::

        <mix:{{ tag }}>
            <mix:degrees>
              <mix:numerator>2</mix:numerator>
              <mix:denominator>1</mix:denominator>
            </mix:degrees>
            <mix:minutes>
              <mix:numerator>2</mix:numerator>
              <mix:denominator>1</mix:denominator>
            </mix:minutes>
            <mix:seconds>
              <mix:numerator>2</mix:numerator>
              <mix:denominator>1</mix:denominator>
            </mix:seconds>
        </mix:{{ tag }}>

    """
    container = _element(tag)

    if degrees:
        degrees_el = _rationaltype_element('degrees', degrees)
        container.append(degrees_el)

    if minutes:
        minutes_el = _rationaltype_element('minutes', minutes)
        container.append(minutes_el)

    if seconds:
        seconds_el = _rationaltype_element('seconds', seconds)
        container.append(seconds_el)

    return container
Ejemplo n.º 7
0
def ycbcr(subsample_horiz=None,
          subsample_vert=None,
          positioning=None,
          luma_red=None,
          luma_green=None,
          luma_blue=None):
    """
    Returns the MIX YCbCr element and its subelements.

    :subsample_horiz: The horizontal subsample factor as a string
    :subsample_vert: The vertical subsample factor as a string
    :positioning: The positions of subsamples as a string
    :luma_red: The red luminance value as a list (or integer)
    :luma_green: The green luminane value as a list (or integer)
    :luma_blue: The blue luminance value as a list (or integer)

    Returns the following sorted ElementTree structure::

        <mix:YCbCr>
          <mix:YCbCrSubSampling>
            <mix:yCbCrSubsampleHoriz>1</mix:yCbCrSubsampleHoriz>
            <mix:yCbCrSubsampleVert>2</mix:yCbCrSubsampleVert>
          </mix:YCbCrSubSampling/>
          <mix:yCbCrPositioning>1</mix:yCbCrPositioning>
          <mix:YCbCrCoefficients>
            <mix:lumaRed>
              <mix:numerator>10</mix:numerator>
              <mix:denominator>1</mix:denominator>
            </mix:lumaRed>
            <mix:lumaGreen>
              <mix:numerator>20</mix:numerator>
              <mix:denominator>1</mix:denominator>
            </mix:lumaGreen>
            <mix:lumaBlue>
              <mix:numerator>30</mix:numerator>
              <mix:denominator>1</mix:denominator>
            </mix:lumaBlue>
          </mix:YCbCrCoefficients/>
        </mix:YCbCr>

    """
    container = _element('YCbCr')

    if subsample_horiz or subsample_vert:
        subsample_container = _subelement(container, 'YCbCrSubSampling')
        if subsample_horiz:
            if subsample_horiz in YCBCR_SUBSAMPLE_TYPES:
                subsample_horiz_el = _subelement(subsample_container,
                                                 'yCbCrSubsampleHoriz')
                subsample_horiz_el.text = subsample_horiz
            else:
                raise RestrictedElementError(subsample_horiz,
                                             'yCbCrSubsampleHoriz',
                                             YCBCR_SUBSAMPLE_TYPES)
        if subsample_vert:
            if subsample_vert in YCBCR_SUBSAMPLE_TYPES:
                subsample_vert_el = _subelement(subsample_container,
                                                'yCbCrSubsampleVert')
                subsample_vert_el.text = subsample_vert
            else:
                raise RestrictedElementError(subsample_vert,
                                             'yCbCrSubsampleVert',
                                             YCBCR_SUBSAMPLE_TYPES)

    if positioning:
        if positioning in YCBCR_POSITIONING_TYPES:
            positioning_el = _subelement(container, 'yCbCrPositioning')
            positioning_el.text = positioning
        else:
            raise RestrictedElementError(positioning, 'yCbCrPositioning',
                                         YCBCR_POSITIONING_TYPES)

    if luma_red or luma_green or luma_blue:
        luma_container = _subelement(container, 'YCbCrCoefficients')
        if luma_red:
            _rationaltype_element('lumaRed', luma_red, parent=luma_container)
        if luma_green:
            _rationaltype_element('lumaGreen',
                                  luma_green,
                                  parent=luma_container)
        if luma_blue:
            _rationaltype_element('lumaBlue', luma_blue, parent=luma_container)

    return container
Ejemplo n.º 8
0
def primary_chromaticities(red_x=None,
                           red_y=None,
                           green_x=None,
                           green_y=None,
                           blue_x=None,
                           blue_y=None):
    """
    Returns the MIX PrimaryChromaticities element.

    :red_x: The red X value for the chromaticities as a list
    :red_x: The red Y value for the chromaticities as a list
    :red_x: The green X value for the chromaticities as a list
    :red_x: The green Y value for the chromaticities as a list
    :red_x: The blue X value for the chromaticities as a list
    :red_x: The blue Y value for the chromaticities as a list

    Returns the following ElementTree structure::

        <mix:PrimaryChromaticities>
          <mix:primaryChromaticitiesRedX>
            <mix:numerator>10</mix:numerator>
            <mix:denominator>1</mix:denominator>
          </mix:primaryChromaticitiesRedX>
          <mix:primaryChromaticitiesRedY>
            <mix:numerator>10</mix:numerator>
            <mix:denominator>1</mix:denominator>
          </mix:primaryChromaticitiesRedY>
          <mix:primaryChromaticitiesGreenX>
            <mix:numerator>10</mix:numerator>
            <mix:denominator>1</mix:denominator>
          </mix:primaryChromaticitiesGreenX>
          <mix:primaryChromaticitiesGreenY>
            <mix:numerator>10</mix:numerator>
            <mix:denominator>1</mix:denominator>
          </mix:primaryChromaticitiesGreenY>
          <mix:primaryChromaticitiesBlueX>
            <mix:numerator>10</mix:numerator>
            <mix:denominator>1</mix:denominator>
          </mix:primaryChromaticitiesBlueX>
          <mix:primaryChromaticitiesBlueY>
            <mix:numerator>10</mix:numerator>
            <mix:denominator>1</mix:denominator>
          </mix:primaryChromaticitiesBlueY>
        </mix:PrimaryChromaticities>

    """
    container = _element('PrimaryChromaticities')

    if red_x:
        _rationaltype_element('primaryChromaticitiesRedX',
                              red_x,
                              parent=container)

    if red_y:
        _rationaltype_element('primaryChromaticitiesRedY',
                              red_y,
                              parent=container)

    if green_x:
        _rationaltype_element('primaryChromaticitiesGreenX',
                              green_x,
                              parent=container)

    if green_y:
        _rationaltype_element('primaryChromaticitiesGreenY',
                              green_y,
                              parent=container)

    if blue_x:
        _rationaltype_element('primaryChromaticitiesBlueX',
                              blue_x,
                              parent=container)

    if blue_y:
        _rationaltype_element('primaryChromaticitiesBlueY',
                              blue_y,
                              parent=container)

    return container
def gps_data(contents=None):
    """
    Returns the MIX GPSData element. The function argument contents
    is a dict, from nisomix.GPS_DATA_CONTENTS. The keys from the
    contents dict are matched to create the MIX element and its
    substructure. The dict should look like this::

        contents = {"version_id": None,
                    "lat_ref": None,
                    "lat_degrees": None,
                    "lat_minutes": None,
                    "lat_seconds": None,
                    "long_ref": None,
                    "long_degrees": None,
                    "long_minutes": None,
                    "long_seconds": None,
                    "altitude_ref": None,
                    "altitude": None,
                    "timestamp": None,
                    "satellites": None,
                    "status": None,
                    "measure_mode": None,
                    "dop": None,
                    "speed_ref": None,
                    "speed": None,
                    "track_ref": None,
                    "track": None,
                    "img_direction_ref": None,
                    "direction": None,
                    "map_datum": None,
                    "dest_lat_ref": None,
                    "dest_lat_degrees": None,
                    "dest_lat_minutes": None,
                    "dest_lat_seconds": None,
                    "dest_long_ref": None,
                    "dest_long_degrees": None,
                    "dest_long_minutes": None,
                    "dest_long_seconds": None,
                    "dest_bearing_ref": None,
                    "dest_bearing": None,
                    "dest_distance_ref": None,
                    "dest_distance": None,
                    "processing_method": None,
                    "area_information": None,
                    "datestamp": None,
                    "differential": None,
                    "gps_groups": None}

    """
    tags = {
        'version_id': 'gpsVersionID',
        'lat_ref': 'gpsLatitudeRef',
        'long_ref': 'gpsLongitudeRef',
        'altitude_ref': 'gpsAltitudeRef',
        'timestamp': 'gpsTimeStamp',
        'satellites': 'gpsSatellites',
        'status': 'gpsStatus',
        'measure_mode': 'gpsMeasureMode',
        'speed_ref': 'gpsSpeedRef',
        'track_ref': 'gpsTrackRef',
        'img_direction_ref': 'gpsImgDirectionRef',
        'map_datum': 'gpsMapDatum',
        'dest_lat_ref': 'gpsDestLatitudeRef',
        'dest_long_ref': 'gpsDestLongitudeRef',
        'dest_bearing_ref': 'gpsDestBearingRef',
        'dest_distance_ref': 'gpsDestDistanceRef',
        'processing_method': 'gpsProcessingMethod',
        'area_information': 'gpsAreaInformation',
        'datestamp': 'gpsDateStamp',
        'differential': 'gpsDifferential'
    }

    rationals = {
        'altitude': 'gpsAltitude',
        'dop': 'gpsDOP',
        'speed': 'gpsSpeed',
        'track': 'gpsTrack',
        'direction': 'gpsImgDirection',
        'dest_bearing': 'gpsDestBearing',
        'dest_distance': 'gpsDestDistance'
    }

    for key in contents:
        if key not in GPS_DATA_CONTENTS:
            raise ValueError('Key "%s" not in supported keys '
                             'for gps_data.' % key)

    container = _element('GPSData')
    child_elements = []

    for key, value in six.iteritems(contents):
        if key in tags and value:
            elem = _element(tags[key])
            elem.text = value
            child_elements.append(elem)

        if key in rationals and value:
            elem = _rationaltype_element(rationals[key], value)
            child_elements.append(elem)

    if contents.get("lat_degrees") or contents.get("lat_minutes") or \
            contents.get("lat_seconds"):
        lat_group = _gps_group('GPSLatitude',
                               degrees=contents["lat_degrees"],
                               minutes=contents["lat_minutes"],
                               seconds=contents["lat_seconds"])
        child_elements.append(lat_group)

    if contents.get("long_degrees") or contents.get("long_minutes") or \
            contents.get("long_seconds"):
        long_group = _gps_group('GPSLongitude',
                                degrees=contents["long_degrees"],
                                minutes=contents["long_minutes"],
                                seconds=contents["long_seconds"])
        child_elements.append(long_group)

    if contents.get("dest_lat_degrees") or \
            contents.get("dest_lat_minutes") or \
            contents.get("dest_lat_seconds"):
        dest_lat_group = _gps_group('GPSDestLatitude',
                                    degrees=contents["dest_lat_degrees"],
                                    minutes=contents["dest_lat_minutes"],
                                    seconds=contents["dest_lat_seconds"])
        child_elements.append(dest_lat_group)

    if contents.get("dest_long_degrees") or \
            contents.get("dest_long_minutes") or \
            contents.get("dest_long_seconds"):
        dest_long_group = _gps_group('GPSDestLongitude',
                                     degrees=contents["dest_long_degrees"],
                                     minutes=contents["dest_long_minutes"],
                                     seconds=contents["dest_long_seconds"])
        child_elements.append(dest_long_group)

    child_elements.sort(key=gps_data_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