예제 #1
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
예제 #2
0
def color_map(reference=None, embedded=None):
    """
    Returns the MIX Colormap element.

    :reference: The location of the referenced color map as a string
    :embedded: The embedded color map as base64-encoded data

    Returns the following ElementTree structure::

        <mix:Colormap>
          <mix:colormapReference>http://foo</mix:colormapReference>
          <mix:embeddedColormap>foo</mix:embeddedColormap>
        </mix:Colormap>

    """
    container = _element('Colormap')

    if reference:
        reference_el = _subelement(container, 'colormapReference')
        reference_el.text = reference

    if embedded:
        embedded_el = _subelement(container, 'embeddedColormap')
        embedded_el.text = six.text_type(embedded)

    return container
def scanning_software(name=None, version=None):
    """
    Returns the MIX ScanningSystemSoftware element.

    :name: The scanning software name as a string
    :version: The scanning software version as a string

    Returns the following sorted ElementTree structure::

        <mix:ScanningSystemSoftware>
          <mix:scanningSoftwareName>foo</mix:scanningSoftwareName>
          <mix:scanningSoftwareVersionNo>foo</mix:scanningSoftwareVersionNo>
        </mix:ScanningSystemSoftware>

    """
    container = _element('ScanningSystemSoftware')

    if name:
        name_el = _subelement(container, 'scanningSoftwareName')
        name_el.text = name

    if version:
        version_el = _subelement(container, 'scanningSoftwareVersionNo')
        version_el.text = version

    return container
예제 #4
0
def format_designation(format_name=None, format_version=None):
    """
    Returns the MIX FormatDesignation element.

    :format_name: The file format name as a string
    :format_version: The file format version as a string

    Returns the following ElementTree structure::

        <mix:FormatDesignation>
          <mix:formatName>image/jpeg</mix:formatName>
          <mix:formatVersion>1.01</mix:formatVersion>
        </mix:FormatDesignation>

    """
    container = _element('FormatDesignation')

    if format_name:
        format_name_el = _subelement(container, 'formatName')
        format_name_el.text = format_name

    if format_version:
        format_version_el = _subelement(container, 'formatVersion')
        format_version_el.text = format_version

    return container
예제 #5
0
def format_registry(registry_name=None, registry_key=None):
    """
    Returns the MIX FormatRegistry element.

    :registry_name: The file format registry name as a string
    :registry_key: The file format registry key as a string

    Returns the following ElementTree structure::

        <mix:FormatRegistry>
          <mix:formatRegistryName>pronom</mix:formatRegistryName>
          <mix:formatRegistryKey>fmt/43</mix:formatRegistryKey>
        </mix:FormatRegistry>

    """
    container = _element('FormatRegistry')

    if registry_name:
        registry_name_el = _subelement(container, 'formatRegistryName')
        registry_name_el.text = registry_name

    if registry_key:
        registry_key_el = _subelement(container, 'formatRegistryKey')
        registry_key_el.text = registry_key

    return container
예제 #6
0
def identifier(id_type=None, id_value=None):
    """
    Returns the MIX ObjectIdentifier element.

    :id_type: The identifier type as a string
    :id_value: The identifier value as a string

    Returns the following ElementTree structure::

        <mix:ObjectIdentifier>
          <mix:objectIdentifierType>local</mix:objectIdentifierType>
          <mix:objectIdentifierValue>foo</mix:objectIdentifierValue>
        </mix:ObjectIdentifier>

    """
    container = _element('ObjectIdentifier')

    if id_type:
        id_type_el = _subelement(container, 'objectIdentifierType')
        id_type_el.text = id_type

    if id_value:
        id_value_el = _subelement(container, 'objectIdentifierValue')
        id_value_el.text = id_value

    return container
예제 #7
0
def image_characteristics(width=None, height=None, child_elements=None):
    """
    Returns the MIX BasicImageCharacteristics element.

    :width: The image width in pixels as an integer
    :height: The image height in pixels as an integer
    :child_elements: Child elements as a list

    Returns the following sorted ElementTree structure::

        <mix:BasicImageCharacteristics>
          <mix:imageWidth>20</mix:imageWidth>
          <mix:imageHeight>10</mix:imageHeight>
          <mix:PhotometricInterpretation/>
        </mix:BasicImageCharacteristics>

    """
    container = _element('BasicImageCharacteristics')

    if width:
        width_el = _subelement(container, 'imageWidth')
        width_el.text = six.text_type(width)
    if height:
        height_el = _subelement(container, 'imageHeight')
        height_el.text = six.text_type(height)
    if child_elements:
        for element in child_elements:
            container.append(element)

    return container
예제 #8
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
def source_id(source_idtype=None, source_idvalue=None):
    """
    Returns the MIX SourceID element.

    :source_idtype: The source ID type as a string
    :source_idvalue: The source ID value as a string

    Returns the following sorted ElementTree structure::

        <mix:SourceID>
          <mix:sourceIDType>local</mix:sourceIDType>
          <mix:sourceIDValue>foo</mix:sourceIDValue>
        </mix:SourceID>

    """
    container = _element('SourceID')

    if source_idtype:
        source_idtype_el = _subelement(container, 'sourceIDType')
        source_idtype_el.text = source_idtype

    if source_idvalue:
        source_idvalue_el = _subelement(container, 'sourceIDValue')
        source_idvalue_el.text = source_idvalue

    return container
예제 #10
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
def processing_software(name=None,
                        version=None,
                        os_name=None,
                        os_version=None):
    """
    Returns the MIX ProcessingSoftware element.

    :name: The processing software name as a string
    :version: The processing software version as a string
    :os_name: The operating system name as a string
    :os_version: The operating system version as a string

    Returns the following ElementTree structure::

        <mix:ProcessingSoftware>
          <mix:processingSoftwareName>
            my software
          </mix:processingSoftwareName>
          <mix:processingsoftwareversion>
            1.0
          </mix:processingsoftwareversion>
          <mix:processingOperatingSystemName>
            CentOS
          </mix:processingOperatingSystemName>
          <mix:processingOperatingSystemVersion>
            7.0
          </mix:processingOperatingSystemVersion>
        </mix:ProcessingSoftware>

    """
    container = _element('ProcessingSoftware')

    if name:
        name_el = _subelement(container, 'processingSoftwareName')
        name_el.text = name

    if version:
        version_el = _subelement(container, 'processingSoftwareVersion')
        version_el.text = version

    if os_name:
        os_name_el = _subelement(container, 'processingOperatingSystemName')
        os_name_el.text = os_name

    if os_version:
        os_version_el = _subelement(container,
                                    'processingOperatingSystemVersion')
        os_version_el.text = os_version

    return container
예제 #12
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
예제 #13
0
def djvu(djvu_format=None):
    """
    Returns the MIX Djvu element. Djvu format supports only a specific
    set of types.

    :djvu_format: The DjVu file format as a string

    Returns the following ElementTree structure::

        <mix:Djvu>
          <mix:djvuFormat>indirect</mix:djvuFormat>
        </mix:Djvu>

    """
    container = _element('Djvu')

    if djvu_format:
        if djvu_format in DJVU_FORMATS:
            djvu_format_el = _subelement(container, 'djvuFormat')
            djvu_format_el.text = djvu_format
        else:
            raise RestrictedElementError(djvu_format, 'djvuFormat',
                                         DJVU_FORMATS)

    return container
예제 #14
0
def photometric_interpretation(color_space=None, child_elements=None):
    """"
    Returns the MIX PhotometricInterpretation element.

    :color_space: The color space as a string
    :child_elements: Child elements as a list

    Returns the following sorted ElementTree structure::

        <mix:PhotometricInterpretation>
          <mix:colorSpace>RGB</mix:colorSpace>
          <mix:ColorProfile/>
          <mix:YCbCr/>
          <mix:ReferenceBlackWhite/>
        </mix:PhotometricInterpretation>

    """
    container = _element('PhotometricInterpretation')

    if color_space:
        color_space_el = _subelement(container, 'colorSpace')
        color_space_el.text = color_space
    if child_elements:
        child_elements.sort(key=photom_interpret_order)
        for element in child_elements:
            container.append(element)

    return container
def device_model(device_type, name=None, number=None, serialno=None):
    """
    Returns either the MIX ScannerModel or the DigitalCameraModel element
    depending on the device_type.

    :device_type: The type of capture device, e.g. 'scanner' or 'camera'
    :name: The model name of the capture device as a string
    :number: The model number of the capture device as a string
    :serialno: The serial number of the capture device as a string

    """
    prefixes = {'scanner': 'scanner', 'camera': 'digitalCamera'}

    if device_type not in prefixes:
        raise ValueError('Invalid value. Only "scanner" or "camera" are '
                         'valid device types.')

    container = _element('model',
                         prefix=prefixes[device_type][0].capitalize() +
                         prefixes[device_type][1:])

    if name:
        device_name_el = _subelement(container,
                                     'modelName',
                                     prefix=prefixes[device_type])
        device_name_el.text = name

    if number:
        device_number_el = _subelement(container,
                                       'modelNumber',
                                       prefix=prefixes[device_type])
        device_number_el.text = number

    if serialno:
        device_serialno_el = _subelement(container,
                                         'modelSerialNo',
                                         prefix=prefixes[device_type])
        device_serialno_el.text = serialno

    return container
예제 #16
0
def target_id(manufacturer=None, name=None, target_no=None, media=None):
    """
    Returns MIX TargetID element.

    :manufacturer: The target manufacturer as a  string
    :name: The target name as a string
    :target_no: The target version or number as a string
    :media: The target media as a string

    Returns the following ElementTree structure::

        <mix:TargetID>
          <mix:targetManufacturer>acme</mix:targetManufacturer>
          <mix:targetName>my target</mix:targetName>
          <mix:targetNo>1.0</mix:targetNo>
          <mix:targetMedia>foo</mix:targetMedia>
        </mix:TargetID>

    """
    container = _element('TargetID')

    if manufacturer:
        manufacturer_el = _subelement(container, 'targetManufacturer')
        manufacturer_el.text = manufacturer

    if name:
        name_el = _subelement(container, 'targetName')
        name_el.text = name

    if target_no:
        target_no_el = _subelement(container, 'targetNo')
        target_no_el.text = target_no

    if media:
        media_el = _subelement(container, 'targetMedia')
        media_el.text = media

    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
예제 #18
0
def fixity(algorithm=None, digest=None, originator=None):
    """
    Returns the MIX Fixity element.

    :algorithm: The message digest algorithm as a string
    :digest: The message digest as a string
    :originator: The message digest creator agent as a string


    Returns the following ElementTree structure::

        <mix:Fixity>
          <mix:messageDigestAlgorithm>MD5</mix:messageDigestAlgorithm>
          <mix:messageDigest>foo</mix:messageDigest>
          <mix:messageDigestOriginator>foo</mix:messageDigestOriginator>
        </mix:Fixity>

    """
    container = _element('Fixity')

    if algorithm:
        if algorithm in DIGEST_ALGORITHMS:
            algorithm_el = _subelement(container, 'messageDigestAlgorithm')
            algorithm_el.text = algorithm
        else:
            raise RestrictedElementError(algorithm, 'messageDigestAlgorithm',
                                         DIGEST_ALGORITHMS)

    if digest:
        digest_el = _subelement(container, 'messageDigest')
        digest_el.text = digest

    if originator:
        originator_el = _subelement(container, 'messageDigestOriginator')
        originator_el.text = originator

    return container
def max_optical_resolution(x_resolution=None, y_resolution=None, unit=None):
    """
    Returns the MIX MaximumOpticalResolution element.

    :x_resolution: The x resolution of the scanning sensor as an integer
    :y_resolution: The y resolution of the scanning sensor as an integer
    :unit: The unit of the scanning sensor resolution as a string

    Returns the following sorted ElementTree structure::

        <mix:MaximumOpticalResolution>
          <mix:xOpticalResolution>foo</mix:xOpticalResolution>
          <mix:yOpticalResolution>foo</mix:yOpticalResolution>
          <mix:opticalResolutionUnit>foo</mix:opticalResolutionUnit>
        </mix:MaximumOpticalResolution>

    """
    container = _element('MaximumOpticalResolution')

    if x_resolution:
        x_resolution_el = _subelement(container, 'xOpticalResolution')
        x_resolution_el.text = six.text_type(x_resolution)

    if y_resolution:
        y_resolution_el = _subelement(container, 'yOpticalResolution')
        y_resolution_el.text = six.text_type(y_resolution)

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

    return container
def test_subelement():
    """
    Tests the _subelement function by asserting that the element was
    created correctly as a child element of its given parent element
    and that the parent element contains the created subelement.
    """
    elem = _element('test')
    subelem = _subelement(elem, 'test', 'pre')

    assert subelem.tag == '{http://www.loc.gov/mix/v20}preTest'
    assert subelem.getparent() == elem
    assert elem.xpath('./*')[0] == subelem
    assert len(elem) == 1
    assert ET.tostring(elem) == ET.tostring(ET.fromstring(
        '<mix:test xmlns:mix="http://www.loc.gov/mix/v20">'
        '<mix:preTest/></mix:test>'))
예제 #21
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
예제 #22
0
def mrsid(zoom_levels=None):
    """
    Returns the MIX MrSID element.

    :zoom_levels: The number of available zoom levels as an integer

    Returns the following ElementTree structure::

        <mix:MrSID>
          <mix:zoomLevels>3</mix:zoomLevels>
        </mix:MrSID>

    """
    container = _element('MrSID')

    if zoom_levels:
        zoom_levels_el = _subelement(container, 'zoomLevels')
        zoom_levels_el.text = six.text_type(zoom_levels)

    return container
예제 #23
0
def jpeg2000(codec=None,
             codec_version=None,
             codestream_profile=None,
             compliance_class=None,
             tile_width=None,
             tile_height=None,
             quality_layers=None,
             resolution_levels=None):
    """
    Returns the MIX JPEG2000 element.

    :codec: The codec name as a string
    :codec_version: The codec version as a string
    :codestream_profile: The codestream profile as a string
    :compliance_class: The compliance class as a string
    :tile_width: The width in pixels of the tiles as an integer
    :tile_height: The height in pixels of the tiles as an integer
    :quality_layers: The number of quality layers as an integer
    :resolution_levels: The number of lower resolution levels as an
                        integer

    Returns the following ElementTree structure::

        <mix:JPEG2000>
          <mix:CodecCompliance>
            <mix:codec></mix:codec>
            <mix:codecVersion></mix:codecVersion>
            <mix:codestreamProfile></mix:codestreamProfile>
            <mix:complianceClass></mix:complianceClass>
          </mix:CodecCompliance>
          <mix:EncodingOptions>
            <mix:Tiles>
              <mix:tileWidth>2</mix:tileWidth>
              <mix:tileHeight>2</mix:tileHeight>
            </mix:Tiles>
            <mix:qualityLayers>10</mix:qualityLayers>
            <mix:resolutionLevels>10</mix:resolutionLevels>
          </mix:EncodingOptions>
        </mix:JPEG2000>

    """
    container = _element('JPEG2000')

    if codec or codec_version or codestream_profile or compliance_class:
        codec_container = _subelement(container, 'CodecCompliance')
        if codec:
            codec_el = _subelement(codec_container, 'codec')
            codec_el.text = codec
        if codec_version:
            codec_version_el = _subelement(codec_container, 'codecVersion')
            codec_version_el.text = codec_version
        if codestream_profile:
            codestream_profile_el = _subelement(codec_container,
                                                'codestreamProfile')
            codestream_profile_el.text = codestream_profile
        if compliance_class:
            compliance_class_el = _subelement(codec_container,
                                              'complianceClass')
            compliance_class_el.text = compliance_class

    tiles_container = None
    if tile_width or tile_height:
        tiles_container = _element('Tiles')
        if tile_width:
            tile_width_el = _subelement(tiles_container, 'tileWidth')
            tile_width_el.text = six.text_type(tile_width)
        if tile_height:
            tile_height_el = _subelement(tiles_container, 'tileHeight')
            tile_height_el.text = six.text_type(tile_height)

    if tiles_container is not None or quality_layers or resolution_levels:
        encoding_options = _subelement(container, 'EncodingOptions')
        if tiles_container is not None:
            encoding_options.append(tiles_container)
        if quality_layers:
            quality_layers_el = _subelement(encoding_options, 'qualityLayers')
            quality_layers_el.text = six.text_type(quality_layers)
        if resolution_levels:
            resolution_levels_el = _subelement(encoding_options,
                                               'resolutionLevels')
            resolution_levels_el.text = six.text_type(resolution_levels)

    return container
예제 #24
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
예제 #25
0
def color_profile(icc_name=None,
                  icc_version=None,
                  icc_uri=None,
                  local_name=None,
                  local_url=None,
                  embedded_profile=None):
    """
    Returns the MIX ColorProfile element and its subelements.

    :icc_name: The name of the used ICC profile as a string
    :icc_version: The version of the used ICC profile as a string
    :icc_uri: The URL/URN of the used ICC profile as a string
    :local_name: The name of the used local color profile as a string
    :local_url: The URL/URN of the used local color profile as a string
    :embedded_profile: The embedded color profile as base64-encoded data

    Returns the following sorted ElementTree structure::

        <mix:ColorProfile>
          <mix:IccProfile>
            <mix:iccProfileName>sRGB</mix:iccProfileName>
            <mix:iccProfileVersion>1</mix:iccProfileVersion>
            <mix:iccProfileURI>http://...</mix:iccProfileURI>
          </mix:IccProfile/>
          <mix:LocalProfile>
            <mix:localProfileName>local RGB</mix:localProfileName>
            <mix:localProfileURL>http://...</mix:localProfileURL>
          </mix:LocalProfile/>
          <mix:embeddedProfile>
            [Base64-encoded data]
          </mix:embeddedProfile>
        </mix:ColorProfile>

    """
    container = _element('ColorProfile')

    if icc_name or icc_version or icc_uri:
        icc_container = _subelement(container, 'IccProfile')
        if icc_name:
            icc_name_el = _subelement(icc_container, 'iccProfileName')
            icc_name_el.text = icc_name
        if icc_version:
            icc_version_el = _subelement(icc_container, 'iccProfileVersion')
            icc_version_el.text = icc_version
        if icc_uri:
            icc_uri_el = _subelement(icc_container, 'iccProfileURI')
            icc_uri_el.text = icc_uri

    if local_name or local_url:
        local_container = _subelement(container, 'LocalProfile')
        if local_name:
            local_name_el = _subelement(local_container, 'localProfileName')
            local_name_el.text = local_name
        if local_url:
            local_url_el = _subelement(local_container, 'localProfileURL')
            local_url_el.text = local_url

    if embedded_profile:
        embedded_profile_el = _subelement(container, 'embeddedProfile')
        embedded_profile_el.text = six.text_type(embedded_profile)

    return container
def source_size(x_value=None,
                x_unit=None,
                y_value=None,
                y_unit=None,
                z_value=None,
                z_unit=None):
    """
    Returns the MIX SourceSize element.

    :x_value: The source X value (width) as an integer
    :x_unit: The unit of the source X value (width) as a string
    :y_value: The source Y value (height) as an integer
    :y_unit: The unit of the source Y value (height) as a string
    :z_value: The source Z value (depth) as an integer
    :z_unit: The unit of the source z value (depth) as a string

    Returns the following sorted ElementTree structure::

        <mix:SourceSize>
          <mix:SourceXDimension>
            <mix:sourceXDimensionValue>1.23</mix:sourceXDimensionValue>
            <mix:sourceXDimensionUnit>mm.</mix:sourceXDimensionUnit>
          </mix:SourceXDimension>
          <mix:SourceYDimension>
            <mix:sourceYDimensionValue>1.23</mix:sourceXDimensionValue>
            <mix:sourceYDimensionUnit>mm.</mix:sourceXDimensionUnit>
          </mix:SourceYDimension>
          <mix:SourceZDimension>
            <mix:sourceZDimensionValue>1.23</mix:sourceXDimensionValue>
            <mix:sourceZDimensionUnit>mm.</mix:sourceXDimensionUnit>
          </mix:SourceZDimension>
        </mix:SourceSize>

    """
    container = _element('SourceSize')

    if x_value or x_unit:
        x_dimension = _subelement(container, 'SourceXDimension')
        if x_value:
            x_value_el = _subelement(x_dimension, 'sourceXDimensionValue')
            x_value_el.text = x_value
        if x_unit:
            if x_unit in DIMENSION_UNITS:
                x_unit_el = _subelement(x_dimension, 'sourceXDimensionUnit')
                x_unit_el.text = x_unit
            else:
                raise RestrictedElementError(x_unit, 'sourceXDimensionUnit',
                                             DIMENSION_UNITS)

    if y_value or y_unit:
        y_dimension = _subelement(container, 'SourceYDimension')
        if y_value:
            y_value_el = _subelement(y_dimension, 'sourceYDimensionValue')
            y_value_el.text = y_value
        if y_unit:
            if y_unit in DIMENSION_UNITS:
                y_unit_el = _subelement(y_dimension, 'sourceYDimensionUnit')
                y_unit_el.text = y_unit
            else:
                raise RestrictedElementError(y_unit, 'sourceYDimensionUnit',
                                             DIMENSION_UNITS)

    if z_value or z_unit:
        z_dimension = _subelement(container, 'SourceZDimension')
        if z_value:
            z_value_el = _subelement(z_dimension, 'sourceZDimensionValue')
            z_value_el.text = z_value
        if z_unit:
            if z_unit in DIMENSION_UNITS:
                z_unit_el = _subelement(z_dimension, 'sourceZDimensionUnit')
                z_unit_el.text = z_unit
            else:
                raise RestrictedElementError(z_unit, 'sourceZDimensionUnit',
                                             DIMENSION_UNITS)

    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