def device_capture(device_type,
                   manufacturer=None,
                   sensor=None,
                   child_elements=None):
    """
    Returns either the MIX ScannerCapture or the DigitalCameraCapture
    element depending on the device_type.

    :device_type: The type of capture device, e.g. 'scanner' or 'camera'
    :manufacturer: The manufacturer of the capture device as a string
    :sensor: The type of image sensor of the capture device as a string
    :child_elements: Child elements as a list

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

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

    if child_elements is None:
        child_elements = []

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

    if manufacturer:
        manufacturer_el = _element('manufacturer',
                                   prefix=prefixes[device_type])
        manufacturer_el.text = manufacturer
        child_elements.append(manufacturer_el)

    if sensor and device_type == 'scanner':
        if sensor in SCANNER_SENSOR_TYPES:
            sensor_el = _element('scannerSensor')
            sensor_el.text = sensor
            child_elements.append(sensor_el)
        else:
            raise RestrictedElementError(sensor, 'scannerSensor',
                                         SCANNER_SENSOR_TYPES)

    if sensor and device_type == 'camera':
        if sensor in CAMERA_SENSOR_TYPES:
            sensor_el = _element('cameraSensor')
            sensor_el.text = sensor
            child_elements.append(sensor_el)
        else:
            raise RestrictedElementError(sensor, 'cameraSensor',
                                         CAMERA_SENSOR_TYPES)

    if device_type == 'scanner':
        child_elements.sort(key=scanner_capture_order)
    if device_type == 'camera':
        child_elements.sort(key=camera_capture_order)

    for element in child_elements:
        container.append(element)

    return container
Example #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
Example #3
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
Example #4
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 #5
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 #6
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 #7
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
Example #8
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 image_capture_metadata(orientation=None,
                           methodology=None,
                           child_elements=None):
    """
    Returns the MIX ImageCaptureMetadata element.

    :orientation: The image orientation as a string
    :methodology: The digitization methodology as a string
    :child_elements: Child elements as a list

    Returns the following sorted ElementTree structure::

        <mix:ImageCaptureMetadata>
          {{ Child elements }}
          <mix:orientation>unknown</mix:orientation>
          <mix:methodology>unknown</mix:methodology>
        </mix:ImageCaptureMetadata>

    """
    if child_elements is None:
        child_elements = []

    container = _element('ImageCaptureMetadata')

    if orientation:
        if orientation in ORIENTATION_TYPES:
            orientation_el = _element('orientation')
            orientation_el.text = orientation
            child_elements.append(orientation_el)
        else:
            raise RestrictedElementError(orientation, 'orientation',
                                         ORIENTATION_TYPES)
    if methodology:
        methodology_el = _element('methodology')
        methodology_el.text = methodology
        child_elements.append(methodology_el)

    child_elements.sort(key=image_capture_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
Example #11
0
def _normalized_byteorder(byte_order):
    """
    Tries to fix the byte_order so that the value corresponds to the
    values allowed in the MIX schema. Normalizes hyphens, underscores
    and capitalized letters. Raises an exception if bytOrder couldn't
    be normalized.

    :byte_order: The input byte order as a string
    :returns: The (fixed) byte order as a string
    """
    byte_order = byte_order.replace('-', ' ').replace('_', ' ')
    byte_order = byte_order.lower()

    if byte_order in BYTE_ORDER_TYPES:
        return byte_order

    if 'big' in byte_order and 'endian' in byte_order:
        return 'big endian'

    if 'little' in byte_order and 'endian' in byte_order:
        return 'little endian'

    raise RestrictedElementError(byte_order, 'byteOrder', BYTE_ORDER_TYPES)
Example #12
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
Example #14
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
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