File: image.py

package info (click to toggle)
python-rosettasciio 0.7.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 144,644 kB
  • sloc: python: 36,638; xml: 2,582; makefile: 20; ansic: 4
file content (102 lines) | stat: -rw-r--r-- 3,266 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# -*- coding: utf-8 -*-
# Copyright 2007-2024 The HyperSpy developers
#
# This file is part of RosettaSciIO.
#
# RosettaSciIO is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# RosettaSciIO is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with RosettaSciIO. If not, see <https://www.gnu.org/licenses/#GPL>.

from PIL.ExifTags import TAGS

CustomTAGS = {
    **TAGS,
    # Customized EXIF TAGS from Renishaw
    0xFEA0: "FocalPlaneXYOrigins",  # 65184
    0xFEA1: "FieldOfViewXY",  # 65185
    0xFEA2: "Unknown",  # 65186, could it be magnification?
}


# from https://exiftool.org/TagNames/EXIF.html
# For tag 0x9210 (37392)
FocalPlaneResolutionUnit_mapping = {
    None: None,
    1: None,
    2: "inches",
    3: "cm",
    4: "mm",
    5: "µm",
}


def _parse_axes_from_metadata(exif_tags, sizes):
    # return of axes must not be empty, or dimensions are lost
    # if no exif_tags exist, axes are set to a scale of 1 per pixel,
    # unit is set to None, hyperspy will parse it as a traits.api.undefined value
    offsets = [0, 0]
    fields_of_views = [sizes[1], sizes[0]]
    unit = None
    if exif_tags is not None:
        # Fallback to default value when tag not available
        offsets = exif_tags.get("FocalPlaneXYOrigins", offsets)
        # jpg files made with Renishaw have this tag
        fields_of_views[0] = exif_tags.get("FocalPlaneXResolution", fields_of_views[0])
        fields_of_views[1] = exif_tags.get("FocalPlaneYResolution", fields_of_views[1])
        unit = FocalPlaneResolutionUnit_mapping[
            exif_tags.get("FocalPlaneResolutionUnit", unit)
        ]

    axes = [
        {
            "name": name,
            "units": unit,
            "size": size,
            "scale": fields_of_views[i] / size,
            "offset": offsets[i],
            "index_in_array": i,
        }
        for i, name, size in zip([1, 0], ["y", "x"], sizes)
    ]

    return axes


def _parse_exif_tags(im):
    """
    Parse exif tags from a pillow image

    Parameters
    ----------
    im : :class:`PIL.Image`
        The pillow image from which the exif tags will be parsed.

    Returns
    -------
    exif_dict : None or dict
        The dictionary of exif tags.

    """
    exif_dict = None
    try:
        # missing header keys when Pillow >= 8.2.0 -> does not flatten IFD anymore
        # see https://pillow.readthedocs.io/en/stable/releasenotes/8.2.0.html#image-getexif-exif-and-gps-ifd
        # Use fall-back _getexif method instead
        # Not all format plugin have the private method
        # prefer to use that method as it returns more items
        exif_dict = im._getexif()
    except AttributeError:
        exif_dict = im.getexif()
    if exif_dict is not None:
        exif_dict = {CustomTAGS.get(k, "unknown"): v for k, v in exif_dict.items()}

    return exif_dict