import re from xml.etree import ElementTree from app.manifest_name_to_discover_name import biolucida_name_map XMP_NS = {'xmp': 'http://ns.adobe.com/xap/1.0/', 'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'x': 'adobe:ns:meta/'} XMP_CORE_REGEXP = r"^XMP Core ([\d]+\.[\d]+\.[\d])$" def _process_5_5_0(xml): xmp_info = {} pixel_width_element = xml.find('.//rdf:Description[@xmp:PixelWidth]', XMP_NS) if pixel_width_element is not None: xmp_info['pixel_width'] = pixel_width_element.attrib[f'{{{XMP_NS["xmp"]}}}PixelWidth'] pixel_height_element = xml.find('.//rdf:Description[@xmp:PixelHeight]', XMP_NS) if pixel_height_element is not None: xmp_info['pixel_height'] = pixel_height_element.attrib[f'{{{XMP_NS["xmp"]}}}PixelHeight'] z_spacing_element = xml.find('.//rdf:Description[@xmp:SizeZ]', XMP_NS) if z_spacing_element is not None: xmp_info['z_spacing'] = z_spacing_element.attrib[f'{{{XMP_NS["xmp"]}}}SizeZ'] if not xmp_info: # As a backup, try processing the xml as version 5.6.0. xmp_info = _process_5_6_0(xml) return xmp_info def _process_5_6_0(xml): xmp_info = {} pixel_width_element = xml.find('.//rdf:li[@xmp:PixelWidth]', XMP_NS) if pixel_width_element is not None: xmp_info['pixel_width'] = pixel_width_element.attrib[f'{{{XMP_NS["xmp"]}}}PixelWidth'] pixel_height_element = xml.find('.//rdf:li[@xmp:PixelHeight]', XMP_NS) if pixel_height_element is not None: xmp_info['pixel_height'] = pixel_height_element.attrib[f'{{{XMP_NS["xmp"]}}}PixelHeight'] z_spacing_element = xml.find('.//rdf:li[@xmp:SpacingZ]', XMP_NS) if z_spacing_element is not None: xmp_info['z_spacing'] = z_spacing_element.attrib[f'{{{XMP_NS["xmp"]}}}SpacingZ'] element = xml.find('.//rdf:li[@xmp:Description]', XMP_NS) if element is not None: image_description = element.attrib[f'{{{XMP_NS["xmp"]}}}Description'] image_description_mbf_map = image_description[image_description.find('') + len(''):] mbf_map = image_description_mbf_map[:image_description_mbf_map.find('')] # Get the modality, expect it to be the same for all channels. matched = re.findall(r'Channel:0:[0-9]+:AcquisitionMode\?([^?]+)\?', mbf_map) matched = list(set(matched)) if len(matched) == 1: xmp_info['modality'] = matched[0] else: xmp_info['modality'] = 'RGB' # Get the channel colours and names. matched_colour = re.findall(r'Channel:0:([0-9]+):Color\?([^?]+)\?', mbf_map) matched_name = re.findall(r'Channel:0:([0-9]+):Name\?([^?]+)\?', mbf_map) if len(matched_colour) == len(matched_name): xmp_info['channel_colours'] = [{}] * len(matched_colour) for name in matched_name: index = int(name[0]) colour_list = [colour[1] for colour in matched_colour if colour[0] == name[0]] colour = int(colour_list[0]) name = name[1] xmp_info['channel_colours'][index] = {'colour': '#{0:06X}'.format((colour >> 8) & 0xffffff), 'label': name} # Determine if image is 3D or 2D. matched = re.findall(r'SizeZ\?([^?]+)\?', mbf_map) if len(matched) == 1: xmp_info['three_d'] = int(matched[0]) > 1 return xmp_info def process_results(data): xml = ElementTree.fromstring(data) xmp_version_string = xml.get(f"{{{XMP_NS['x']}}}xmptk") match = re.match(XMP_CORE_REGEXP, xmp_version_string) if match is not None: version = match.group(1) handling_function_name = f"_process_{version.replace('.', '_')}" handling_function = globals().get(handling_function_name, None) if handling_function is not None: return handling_function(xml) raise NotImplementedError(f"Not able to handle XMP core meta data for version: '{version}'") raise AttributeError(f"Not able to match version from: '{xmp_version_string}'") def process_result(data): if 'name' in data: image_name = data['name'] if image_name in biolucida_name_map: data['name'] = biolucida_name_map[image_name] return data