1cc1dc7a3Sopenharmony_ci# SPDX-License-Identifier: Apache-2.0 2cc1dc7a3Sopenharmony_ci# ----------------------------------------------------------------------------- 3cc1dc7a3Sopenharmony_ci# Copyright 2019-2022 Arm Limited 4cc1dc7a3Sopenharmony_ci# 5cc1dc7a3Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); you may not 6cc1dc7a3Sopenharmony_ci# use this file except in compliance with the License. You may obtain a copy 7cc1dc7a3Sopenharmony_ci# of the License at: 8cc1dc7a3Sopenharmony_ci# 9cc1dc7a3Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 10cc1dc7a3Sopenharmony_ci# 11cc1dc7a3Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software 12cc1dc7a3Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13cc1dc7a3Sopenharmony_ci# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14cc1dc7a3Sopenharmony_ci# License for the specific language governing permissions and limitations 15cc1dc7a3Sopenharmony_ci# under the License. 16cc1dc7a3Sopenharmony_ci# ----------------------------------------------------------------------------- 17cc1dc7a3Sopenharmony_ci""" 18cc1dc7a3Sopenharmony_ciThis module contains code for loading image metadata from a file path on disk. 19cc1dc7a3Sopenharmony_ci 20cc1dc7a3Sopenharmony_ciThe directory path is structured: 21cc1dc7a3Sopenharmony_ci 22cc1dc7a3Sopenharmony_ci TestSetName/TestFormat/FileName 23cc1dc7a3Sopenharmony_ci 24cc1dc7a3Sopenharmony_ci... and the file name is structured: 25cc1dc7a3Sopenharmony_ci 26cc1dc7a3Sopenharmony_ci colorProfile-colorFormat-name[-flags].extension 27cc1dc7a3Sopenharmony_ci""" 28cc1dc7a3Sopenharmony_ci 29cc1dc7a3Sopenharmony_cifrom collections.abc import Iterable 30cc1dc7a3Sopenharmony_ciimport os 31cc1dc7a3Sopenharmony_ciimport re 32cc1dc7a3Sopenharmony_ciimport subprocess as sp 33cc1dc7a3Sopenharmony_ci 34cc1dc7a3Sopenharmony_cifrom PIL import Image as PILImage 35cc1dc7a3Sopenharmony_ci 36cc1dc7a3Sopenharmony_ciimport testlib.misc as misc 37cc1dc7a3Sopenharmony_ci 38cc1dc7a3Sopenharmony_ci 39cc1dc7a3Sopenharmony_ciCONVERT_BINARY = ["convert"] 40cc1dc7a3Sopenharmony_ci 41cc1dc7a3Sopenharmony_ci 42cc1dc7a3Sopenharmony_ciclass ImageException(Exception): 43cc1dc7a3Sopenharmony_ci """ 44cc1dc7a3Sopenharmony_ci Exception thrown for bad image specification. 45cc1dc7a3Sopenharmony_ci """ 46cc1dc7a3Sopenharmony_ci 47cc1dc7a3Sopenharmony_ci 48cc1dc7a3Sopenharmony_ciclass TestImage(): 49cc1dc7a3Sopenharmony_ci """ 50cc1dc7a3Sopenharmony_ci Objects of this type contain metadata for a single test image on disk. 51cc1dc7a3Sopenharmony_ci 52cc1dc7a3Sopenharmony_ci Attributes: 53cc1dc7a3Sopenharmony_ci filePath: The path of the file on disk. 54cc1dc7a3Sopenharmony_ci outFilePath: The path of the output file on disk. 55cc1dc7a3Sopenharmony_ci testSet: The name of the test set. 56cc1dc7a3Sopenharmony_ci testFormat: The test format group. 57cc1dc7a3Sopenharmony_ci testFile: The test file name. 58cc1dc7a3Sopenharmony_ci colorProfile: The image compression color profile. 59cc1dc7a3Sopenharmony_ci colorFormat: The image color format. 60cc1dc7a3Sopenharmony_ci name: The image human name. 61cc1dc7a3Sopenharmony_ci is3D: True if the image is 3D, else False. 62cc1dc7a3Sopenharmony_ci isAlphaScaled: True if the image wants alpha scaling, else False. 63cc1dc7a3Sopenharmony_ci TEST_EXTS: Expected test image extensions. 64cc1dc7a3Sopenharmony_ci PROFILES: Tuple of valid color profile values. 65cc1dc7a3Sopenharmony_ci FORMATS: Tuple of valid color format values. 66cc1dc7a3Sopenharmony_ci FLAGS: Map of valid flags (key) and their meaning (value). 67cc1dc7a3Sopenharmony_ci """ 68cc1dc7a3Sopenharmony_ci TEST_EXTS = (".jpg", ".png", ".tga", ".dds", ".hdr", ".ktx") 69cc1dc7a3Sopenharmony_ci 70cc1dc7a3Sopenharmony_ci PROFILES = ("ldr", "ldrs", "hdr") 71cc1dc7a3Sopenharmony_ci 72cc1dc7a3Sopenharmony_ci FORMATS = ("l", "la", "xy", "rgb", "rgba") 73cc1dc7a3Sopenharmony_ci 74cc1dc7a3Sopenharmony_ci FLAGS = { 75cc1dc7a3Sopenharmony_ci # Flags for image compression control 76cc1dc7a3Sopenharmony_ci "3": "3D image", 77cc1dc7a3Sopenharmony_ci "m": "Mask image", 78cc1dc7a3Sopenharmony_ci "a": "Alpha scaled image" 79cc1dc7a3Sopenharmony_ci } 80cc1dc7a3Sopenharmony_ci 81cc1dc7a3Sopenharmony_ci def __init__(self, filePath): 82cc1dc7a3Sopenharmony_ci """ 83cc1dc7a3Sopenharmony_ci Create a new image definition, based on a structured file path. 84cc1dc7a3Sopenharmony_ci 85cc1dc7a3Sopenharmony_ci Args: 86cc1dc7a3Sopenharmony_ci filePath (str): The path of the image on disk. 87cc1dc7a3Sopenharmony_ci 88cc1dc7a3Sopenharmony_ci Raises: 89cc1dc7a3Sopenharmony_ci ImageException: The image couldn't be found or is unstructured. 90cc1dc7a3Sopenharmony_ci """ 91cc1dc7a3Sopenharmony_ci self.filePath = os.path.abspath(filePath) 92cc1dc7a3Sopenharmony_ci if not os.path.exists(self.filePath): 93cc1dc7a3Sopenharmony_ci raise ImageException("Image doesn't exist (%s)" % filePath) 94cc1dc7a3Sopenharmony_ci 95cc1dc7a3Sopenharmony_ci # Decode the path 96cc1dc7a3Sopenharmony_ci scriptDir = os.path.dirname(__file__) 97cc1dc7a3Sopenharmony_ci rootInDir = os.path.join(scriptDir, "..", "Images") 98cc1dc7a3Sopenharmony_ci partialPath = os.path.relpath(self.filePath, rootInDir) 99cc1dc7a3Sopenharmony_ci parts = misc.path_splitall(partialPath) 100cc1dc7a3Sopenharmony_ci if len(parts) != 3: 101cc1dc7a3Sopenharmony_ci raise ImageException("Image path not path triplet (%s)" % parts) 102cc1dc7a3Sopenharmony_ci self.testSet = parts[0] 103cc1dc7a3Sopenharmony_ci self.testFormat = parts[1] 104cc1dc7a3Sopenharmony_ci self.testFile = parts[2] 105cc1dc7a3Sopenharmony_ci 106cc1dc7a3Sopenharmony_ci # Decode the file name 107cc1dc7a3Sopenharmony_ci self.decode_file_name(self.testFile) 108cc1dc7a3Sopenharmony_ci 109cc1dc7a3Sopenharmony_ci # Output file path (store base without extension) 110cc1dc7a3Sopenharmony_ci rootOutDir = os.path.join(scriptDir, "..", "..", "TestOutput") 111cc1dc7a3Sopenharmony_ci outFilePath = os.path.join(rootOutDir, partialPath) 112cc1dc7a3Sopenharmony_ci outFilePath = os.path.abspath(outFilePath) 113cc1dc7a3Sopenharmony_ci outFilePath = os.path.splitext(outFilePath)[0] 114cc1dc7a3Sopenharmony_ci self.outFilePath = outFilePath 115cc1dc7a3Sopenharmony_ci 116cc1dc7a3Sopenharmony_ci def decode_file_name(self, fileName): 117cc1dc7a3Sopenharmony_ci """ 118cc1dc7a3Sopenharmony_ci Utility function to decode metadata from an encoded file name. 119cc1dc7a3Sopenharmony_ci 120cc1dc7a3Sopenharmony_ci Args: 121cc1dc7a3Sopenharmony_ci fileName (str): The file name to tokenize. 122cc1dc7a3Sopenharmony_ci 123cc1dc7a3Sopenharmony_ci Raises: 124cc1dc7a3Sopenharmony_ci ImageException: The image file path is badly structured. 125cc1dc7a3Sopenharmony_ci """ 126cc1dc7a3Sopenharmony_ci # Strip off the extension 127cc1dc7a3Sopenharmony_ci rootName = os.path.splitext(fileName)[0] 128cc1dc7a3Sopenharmony_ci 129cc1dc7a3Sopenharmony_ci parts = rootName.split("-") 130cc1dc7a3Sopenharmony_ci 131cc1dc7a3Sopenharmony_ci # Decode the mandatory fields 132cc1dc7a3Sopenharmony_ci if len(parts) >= 3: 133cc1dc7a3Sopenharmony_ci self.colorProfile = parts[0] 134cc1dc7a3Sopenharmony_ci if self.colorProfile not in self.PROFILES: 135cc1dc7a3Sopenharmony_ci raise ImageException("Unknown color profile (%s)" % parts[0]) 136cc1dc7a3Sopenharmony_ci 137cc1dc7a3Sopenharmony_ci self.colorFormat = parts[1] 138cc1dc7a3Sopenharmony_ci if self.colorFormat not in self.FORMATS: 139cc1dc7a3Sopenharmony_ci raise ImageException("Unknown color format (%s)" % parts[1]) 140cc1dc7a3Sopenharmony_ci 141cc1dc7a3Sopenharmony_ci # Consistency check between directory and file names 142cc1dc7a3Sopenharmony_ci reencode = "%s-%s" % (self.colorProfile, self.colorFormat) 143cc1dc7a3Sopenharmony_ci compare = self.testFormat.lower() 144cc1dc7a3Sopenharmony_ci if reencode != compare: 145cc1dc7a3Sopenharmony_ci dat = (self.testFormat, reencode) 146cc1dc7a3Sopenharmony_ci raise ImageException("Mismatched test and image (%s:%s)" % dat) 147cc1dc7a3Sopenharmony_ci 148cc1dc7a3Sopenharmony_ci self.name = parts[2] 149cc1dc7a3Sopenharmony_ci 150cc1dc7a3Sopenharmony_ci # Set default values for the optional fields 151cc1dc7a3Sopenharmony_ci self.is3D = False 152cc1dc7a3Sopenharmony_ci self.isAlphaScaled = False 153cc1dc7a3Sopenharmony_ci 154cc1dc7a3Sopenharmony_ci # Decode the flags field if present 155cc1dc7a3Sopenharmony_ci if len(parts) >= 4: 156cc1dc7a3Sopenharmony_ci flags = parts[3] 157cc1dc7a3Sopenharmony_ci seenFlags = set() 158cc1dc7a3Sopenharmony_ci for flag in flags: 159cc1dc7a3Sopenharmony_ci if flag in seenFlags: 160cc1dc7a3Sopenharmony_ci raise ImageException("Duplicate flag (%s)" % flag) 161cc1dc7a3Sopenharmony_ci if flag not in self.FLAGS: 162cc1dc7a3Sopenharmony_ci raise ImageException("Unknown flag (%s)" % flag) 163cc1dc7a3Sopenharmony_ci seenFlags.add(flag) 164cc1dc7a3Sopenharmony_ci 165cc1dc7a3Sopenharmony_ci self.is3D = "3" in seenFlags 166cc1dc7a3Sopenharmony_ci self.isAlphaScaled = "a" in seenFlags 167cc1dc7a3Sopenharmony_ci 168cc1dc7a3Sopenharmony_ci def get_size(self): 169cc1dc7a3Sopenharmony_ci """ 170cc1dc7a3Sopenharmony_ci Get the dimensions of this test image, if format is known. 171cc1dc7a3Sopenharmony_ci 172cc1dc7a3Sopenharmony_ci Known cases today where the format is not known: 173cc1dc7a3Sopenharmony_ci 174cc1dc7a3Sopenharmony_ci * 3D .dds files. 175cc1dc7a3Sopenharmony_ci * Any .ktx, .hdr, .exr, or .astc file. 176cc1dc7a3Sopenharmony_ci 177cc1dc7a3Sopenharmony_ci Returns: 178cc1dc7a3Sopenharmony_ci tuple(int, int): The dimensions of a 2D image, or ``None`` if PIL 179cc1dc7a3Sopenharmony_ci could not open the file. 180cc1dc7a3Sopenharmony_ci """ 181cc1dc7a3Sopenharmony_ci try: 182cc1dc7a3Sopenharmony_ci img = PILImage.open(self.filePath) 183cc1dc7a3Sopenharmony_ci except IOError: 184cc1dc7a3Sopenharmony_ci # HDR files 185cc1dc7a3Sopenharmony_ci return None 186cc1dc7a3Sopenharmony_ci except NotImplementedError: 187cc1dc7a3Sopenharmony_ci # DDS files 188cc1dc7a3Sopenharmony_ci return None 189cc1dc7a3Sopenharmony_ci 190cc1dc7a3Sopenharmony_ci return (img.size[0], img.size[1]) 191cc1dc7a3Sopenharmony_ci 192cc1dc7a3Sopenharmony_ci 193cc1dc7a3Sopenharmony_ciclass Image(): 194cc1dc7a3Sopenharmony_ci """ 195cc1dc7a3Sopenharmony_ci Wrapper around an image on the file system. 196cc1dc7a3Sopenharmony_ci """ 197cc1dc7a3Sopenharmony_ci 198cc1dc7a3Sopenharmony_ci # TODO: We don't support KTX yet, as ImageMagick doesn't. 199cc1dc7a3Sopenharmony_ci SUPPORTED_LDR = ["bmp", "jpg", "png", "tga"] 200cc1dc7a3Sopenharmony_ci SUPPORTED_HDR = ["exr", "hdr"] 201cc1dc7a3Sopenharmony_ci 202cc1dc7a3Sopenharmony_ci @classmethod 203cc1dc7a3Sopenharmony_ci def is_format_supported(cls, fileFormat, profile=None): 204cc1dc7a3Sopenharmony_ci """ 205cc1dc7a3Sopenharmony_ci Test if a given file format is supported by the library. 206cc1dc7a3Sopenharmony_ci 207cc1dc7a3Sopenharmony_ci Args: 208cc1dc7a3Sopenharmony_ci fileFormat (str): The file extension (excluding the "."). 209cc1dc7a3Sopenharmony_ci profile (str or None): The profile (ldr or hdr) of the image. 210cc1dc7a3Sopenharmony_ci 211cc1dc7a3Sopenharmony_ci Returns: 212cc1dc7a3Sopenharmony_ci bool: `True` if the image is supported, `False` otherwise. 213cc1dc7a3Sopenharmony_ci """ 214cc1dc7a3Sopenharmony_ci assert profile in [None, "ldr", "hdr"] 215cc1dc7a3Sopenharmony_ci 216cc1dc7a3Sopenharmony_ci if profile == "ldr": 217cc1dc7a3Sopenharmony_ci return fileFormat in cls.SUPPORTED_LDR 218cc1dc7a3Sopenharmony_ci 219cc1dc7a3Sopenharmony_ci if profile == "hdr": 220cc1dc7a3Sopenharmony_ci return fileFormat in cls.SUPPORTED_HDR 221cc1dc7a3Sopenharmony_ci 222cc1dc7a3Sopenharmony_ci return fileFormat in cls.SUPPORTED_LDR or \ 223cc1dc7a3Sopenharmony_ci fileFormat in cls.SUPPORTED_HDR 224cc1dc7a3Sopenharmony_ci 225cc1dc7a3Sopenharmony_ci def __init__(self, filePath): 226cc1dc7a3Sopenharmony_ci """ 227cc1dc7a3Sopenharmony_ci Construct a new Image. 228cc1dc7a3Sopenharmony_ci 229cc1dc7a3Sopenharmony_ci Args: 230cc1dc7a3Sopenharmony_ci filePath (str): The path to the image on disk. 231cc1dc7a3Sopenharmony_ci """ 232cc1dc7a3Sopenharmony_ci self.filePath = filePath 233cc1dc7a3Sopenharmony_ci self.proxyPath = None 234cc1dc7a3Sopenharmony_ci 235cc1dc7a3Sopenharmony_ci def get_colors(self, coords): 236cc1dc7a3Sopenharmony_ci """ 237cc1dc7a3Sopenharmony_ci Get the image colors at the given coordinate. 238cc1dc7a3Sopenharmony_ci 239cc1dc7a3Sopenharmony_ci Args: 240cc1dc7a3Sopenharmony_ci coords (tuple or list): A single coordinate, or a list of 241cc1dc7a3Sopenharmony_ci coordinates to sample. 242cc1dc7a3Sopenharmony_ci 243cc1dc7a3Sopenharmony_ci Returns: 244cc1dc7a3Sopenharmony_ci tuple: A single sample color (if `coords` was a coordinate). 245cc1dc7a3Sopenharmony_ci list: A list of sample colors (if `coords` was a list). 246cc1dc7a3Sopenharmony_ci 247cc1dc7a3Sopenharmony_ci Colors are returned as float values between 0.0 and 1.0 for LDR, 248cc1dc7a3Sopenharmony_ci and float values which may exceed 1.0 for HDR. 249cc1dc7a3Sopenharmony_ci """ 250cc1dc7a3Sopenharmony_ci colors = [] 251cc1dc7a3Sopenharmony_ci 252cc1dc7a3Sopenharmony_ci # We accept both a list of positions and a single position; 253cc1dc7a3Sopenharmony_ci # canonicalize here so the main processing only handles lists 254cc1dc7a3Sopenharmony_ci isList = len(coords) != 0 and isinstance(coords[0], Iterable) 255cc1dc7a3Sopenharmony_ci 256cc1dc7a3Sopenharmony_ci if not isList: 257cc1dc7a3Sopenharmony_ci coords = [coords] 258cc1dc7a3Sopenharmony_ci 259cc1dc7a3Sopenharmony_ci for (x, y) in coords: 260cc1dc7a3Sopenharmony_ci command = list(CONVERT_BINARY) 261cc1dc7a3Sopenharmony_ci command += [self.filePath] 262cc1dc7a3Sopenharmony_ci 263cc1dc7a3Sopenharmony_ci # Ensure convert factors in format origin if needed 264cc1dc7a3Sopenharmony_ci command += ["-auto-orient"] 265cc1dc7a3Sopenharmony_ci 266cc1dc7a3Sopenharmony_ci command += [ 267cc1dc7a3Sopenharmony_ci "-format", "%%[pixel:p{%u,%u}]" % (x, y), 268cc1dc7a3Sopenharmony_ci "info:" 269cc1dc7a3Sopenharmony_ci ] 270cc1dc7a3Sopenharmony_ci 271cc1dc7a3Sopenharmony_ci if os.name == 'nt': 272cc1dc7a3Sopenharmony_ci command.insert(0, "magick") 273cc1dc7a3Sopenharmony_ci 274cc1dc7a3Sopenharmony_ci result = sp.run(command, stdout=sp.PIPE, stderr=sp.PIPE, 275cc1dc7a3Sopenharmony_ci check=True, universal_newlines=True) 276cc1dc7a3Sopenharmony_ci 277cc1dc7a3Sopenharmony_ci rawcolor = result.stdout.strip() 278cc1dc7a3Sopenharmony_ci 279cc1dc7a3Sopenharmony_ci # Decode ImageMagick's annoying named color outputs. Note that this 280cc1dc7a3Sopenharmony_ci # only handles "known" cases triggered by our test images, we don't 281cc1dc7a3Sopenharmony_ci # support the entire ImageMagick named color table. 282cc1dc7a3Sopenharmony_ci if rawcolor == "black": 283cc1dc7a3Sopenharmony_ci colors.append([0.0, 0.0, 0.0, 1.0]) 284cc1dc7a3Sopenharmony_ci elif rawcolor == "white": 285cc1dc7a3Sopenharmony_ci colors.append([1.0, 1.0, 1.0, 1.0]) 286cc1dc7a3Sopenharmony_ci elif rawcolor == "red": 287cc1dc7a3Sopenharmony_ci colors.append([1.0, 0.0, 0.0, 1.0]) 288cc1dc7a3Sopenharmony_ci elif rawcolor == "blue": 289cc1dc7a3Sopenharmony_ci colors.append([0.0, 0.0, 1.0, 1.0]) 290cc1dc7a3Sopenharmony_ci 291cc1dc7a3Sopenharmony_ci # Decode ImageMagick's format tuples 292cc1dc7a3Sopenharmony_ci elif rawcolor.startswith("srgba"): 293cc1dc7a3Sopenharmony_ci rawcolor = rawcolor[6:] 294cc1dc7a3Sopenharmony_ci rawcolor = rawcolor[:-1] 295cc1dc7a3Sopenharmony_ci channels = rawcolor.split(",") 296cc1dc7a3Sopenharmony_ci for i, channel in enumerate(channels): 297cc1dc7a3Sopenharmony_ci if (i < 3) and channel.endswith("%"): 298cc1dc7a3Sopenharmony_ci channels[i] = float(channel[:-1]) / 100.0 299cc1dc7a3Sopenharmony_ci elif (i < 3) and not channel.endswith("%"): 300cc1dc7a3Sopenharmony_ci channels[i] = float(channel) / 255.0 301cc1dc7a3Sopenharmony_ci else: 302cc1dc7a3Sopenharmony_ci channels[i] = float(channel) 303cc1dc7a3Sopenharmony_ci colors.append(channels) 304cc1dc7a3Sopenharmony_ci elif rawcolor.startswith("srgb"): 305cc1dc7a3Sopenharmony_ci rawcolor = rawcolor[5:] 306cc1dc7a3Sopenharmony_ci rawcolor = rawcolor[:-1] 307cc1dc7a3Sopenharmony_ci channels = rawcolor.split(",") 308cc1dc7a3Sopenharmony_ci for i, channel in enumerate(channels): 309cc1dc7a3Sopenharmony_ci if (i < 3) and channel.endswith("%"): 310cc1dc7a3Sopenharmony_ci channels[i] = float(channel[:-1]) / 100.0 311cc1dc7a3Sopenharmony_ci if (i < 3) and not channel.endswith("%"): 312cc1dc7a3Sopenharmony_ci channels[i] = float(channel) / 255.0 313cc1dc7a3Sopenharmony_ci channels.append(1.0) 314cc1dc7a3Sopenharmony_ci colors.append(channels) 315cc1dc7a3Sopenharmony_ci elif rawcolor.startswith("rgba"): 316cc1dc7a3Sopenharmony_ci rawcolor = rawcolor[5:] 317cc1dc7a3Sopenharmony_ci rawcolor = rawcolor[:-1] 318cc1dc7a3Sopenharmony_ci channels = rawcolor.split(",") 319cc1dc7a3Sopenharmony_ci for i, channel in enumerate(channels): 320cc1dc7a3Sopenharmony_ci if (i < 3) and channel.endswith("%"): 321cc1dc7a3Sopenharmony_ci channels[i] = float(channel[:-1]) / 100.0 322cc1dc7a3Sopenharmony_ci elif (i < 3) and not channel.endswith("%"): 323cc1dc7a3Sopenharmony_ci channels[i] = float(channel) / 255.0 324cc1dc7a3Sopenharmony_ci else: 325cc1dc7a3Sopenharmony_ci channels[i] = float(channel) 326cc1dc7a3Sopenharmony_ci colors.append(channels) 327cc1dc7a3Sopenharmony_ci elif rawcolor.startswith("rgb"): 328cc1dc7a3Sopenharmony_ci rawcolor = rawcolor[4:] 329cc1dc7a3Sopenharmony_ci rawcolor = rawcolor[:-1] 330cc1dc7a3Sopenharmony_ci channels = rawcolor.split(",") 331cc1dc7a3Sopenharmony_ci for i, channel in enumerate(channels): 332cc1dc7a3Sopenharmony_ci if (i < 3) and channel.endswith("%"): 333cc1dc7a3Sopenharmony_ci channels[i] = float(channel[:-1]) / 100.0 334cc1dc7a3Sopenharmony_ci if (i < 3) and not channel.endswith("%"): 335cc1dc7a3Sopenharmony_ci channels[i] = float(channel) / 255.0 336cc1dc7a3Sopenharmony_ci channels.append(1.0) 337cc1dc7a3Sopenharmony_ci colors.append(channels) 338cc1dc7a3Sopenharmony_ci else: 339cc1dc7a3Sopenharmony_ci print(x, y) 340cc1dc7a3Sopenharmony_ci print(rawcolor) 341cc1dc7a3Sopenharmony_ci assert False 342cc1dc7a3Sopenharmony_ci 343cc1dc7a3Sopenharmony_ci # ImageMagick decodes DDS files as BGRA not RGBA; manually correct 344cc1dc7a3Sopenharmony_ci if self.filePath.endswith("dds"): 345cc1dc7a3Sopenharmony_ci for color in colors: 346cc1dc7a3Sopenharmony_ci tmp = color[0] 347cc1dc7a3Sopenharmony_ci color[0] = color[2] 348cc1dc7a3Sopenharmony_ci color[2] = tmp 349cc1dc7a3Sopenharmony_ci 350cc1dc7a3Sopenharmony_ci # ImageMagick decodes EXR files with premult alpha; manually correct 351cc1dc7a3Sopenharmony_ci if self.filePath.endswith("exr"): 352cc1dc7a3Sopenharmony_ci for color in colors: 353cc1dc7a3Sopenharmony_ci color[0] /= color[3] 354cc1dc7a3Sopenharmony_ci color[1] /= color[3] 355cc1dc7a3Sopenharmony_ci color[2] /= color[3] 356cc1dc7a3Sopenharmony_ci 357cc1dc7a3Sopenharmony_ci # Undo list canonicalization if we were given a single scalar coord 358cc1dc7a3Sopenharmony_ci if not isList: 359cc1dc7a3Sopenharmony_ci return colors[0] 360cc1dc7a3Sopenharmony_ci 361cc1dc7a3Sopenharmony_ci return colors 362