Download third_party/ktx-src/external/astc-encoder/Test/testlib/image.py from kimjunhan/vkgs-sim: direct link, hf CLI and curl.
- Browser
- Download file 12.6 kB
-
https://huggingface.co/kimjunhan/vkgs-sim/resolve/main/third_party/ktx-src/external/astc-encoder/Test/testlib/image.py
- Command line
-
hf download hf://kimjunhan/vkgs-sim/third_party/ktx-src/external/astc-encoder/Test/testlib/image.py
-
curl -L -o image.py https://huggingface.co/kimjunhan/vkgs-sim/resolve/main/third_party/ktx-src/external/astc-encoder/Test/testlib/image.py
12.6 kB
| # SPDX-License-Identifier: Apache-2.0 | |
| # ----------------------------------------------------------------------------- | |
| # Copyright 2019-2022 Arm Limited | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may not | |
| # use this file except in compliance with the License. You may obtain a copy | |
| # of the License at: | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
| # License for the specific language governing permissions and limitations | |
| # under the License. | |
| # ----------------------------------------------------------------------------- | |
| """ | |
| This module contains code for loading image metadata from a file path on disk. | |
| The directory path is structured: | |
| TestSetName/TestFormat/FileName | |
| and the file name is structured: | |
| colorProfile-colorFormat-name[-flags].extension | |
| """ | |
| from collections.abc import Iterable | |
| import os | |
| import re | |
| import subprocess as sp | |
| from PIL import Image as PILImage | |
| import testlib.misc as misc | |
| CONVERT_BINARY = ["convert"] | |
| class ImageException(Exception): | |
| """ | |
| Exception thrown for bad image specification. | |
| """ | |
| class TestImage(): | |
| """ | |
| Objects of this type contain metadata for a single test image on disk. | |
| Attributes: | |
| filePath: The path of the file on disk. | |
| outFilePath: The path of the output file on disk. | |
| testSet: The name of the test set. | |
| testFormat: The test format group. | |
| testFile: The test file name. | |
| colorProfile: The image compression color profile. | |
| colorFormat: The image color format. | |
| name: The image human name. | |
| is3D: True if the image is 3D, else False. | |
| isAlphaScaled: True if the image wants alpha scaling, else False. | |
| TEST_EXTS: Expected test image extensions. | |
| PROFILES: Tuple of valid color profile values. | |
| FORMATS: Tuple of valid color format values. | |
| FLAGS: Map of valid flags (key) and their meaning (value). | |
| """ | |
| TEST_EXTS = (".jpg", ".png", ".tga", ".dds", ".hdr", ".ktx") | |
| PROFILES = ("ldr", "ldrs", "hdr") | |
| FORMATS = ("l", "la", "xy", "rgb", "rgba") | |
| FLAGS = { | |
| # Flags for image compression control | |
| "3": "3D image", | |
| "m": "Mask image", | |
| "a": "Alpha scaled image" | |
| } | |
| def __init__(self, filePath): | |
| """ | |
| Create a new image definition, based on a structured file path. | |
| Args: | |
| filePath (str): The path of the image on disk. | |
| Raises: | |
| ImageException: The image couldn't be found or is unstructured. | |
| """ | |
| self.filePath = os.path.abspath(filePath) | |
| if not os.path.exists(self.filePath): | |
| raise ImageException("Image doesn't exist (%s)" % filePath) | |
| # Decode the path | |
| scriptDir = os.path.dirname(__file__) | |
| rootInDir = os.path.join(scriptDir, "..", "Images") | |
| partialPath = os.path.relpath(self.filePath, rootInDir) | |
| parts = misc.path_splitall(partialPath) | |
| if len(parts) != 3: | |
| raise ImageException("Image path not path triplet (%s)" % parts) | |
| self.testSet = parts[0] | |
| self.testFormat = parts[1] | |
| self.testFile = parts[2] | |
| # Decode the file name | |
| self.decode_file_name(self.testFile) | |
| # Output file path (store base without extension) | |
| rootOutDir = os.path.join(scriptDir, "..", "..", "TestOutput") | |
| outFilePath = os.path.join(rootOutDir, partialPath) | |
| outFilePath = os.path.abspath(outFilePath) | |
| outFilePath = os.path.splitext(outFilePath)[0] | |
| self.outFilePath = outFilePath | |
| def decode_file_name(self, fileName): | |
| """ | |
| Utility function to decode metadata from an encoded file name. | |
| Args: | |
| fileName (str): The file name to tokenize. | |
| Raises: | |
| ImageException: The image file path is badly structured. | |
| """ | |
| # Strip off the extension | |
| rootName = os.path.splitext(fileName)[0] | |
| parts = rootName.split("-") | |
| # Decode the mandatory fields | |
| if len(parts) >= 3: | |
| self.colorProfile = parts[0] | |
| if self.colorProfile not in self.PROFILES: | |
| raise ImageException("Unknown color profile (%s)" % parts[0]) | |
| self.colorFormat = parts[1] | |
| if self.colorFormat not in self.FORMATS: | |
| raise ImageException("Unknown color format (%s)" % parts[1]) | |
| # Consistency check between directory and file names | |
| reencode = "%s-%s" % (self.colorProfile, self.colorFormat) | |
| compare = self.testFormat.lower() | |
| if reencode != compare: | |
| dat = (self.testFormat, reencode) | |
| raise ImageException("Mismatched test and image (%s:%s)" % dat) | |
| self.name = parts[2] | |
| # Set default values for the optional fields | |
| self.is3D = False | |
| self.isAlphaScaled = False | |
| # Decode the flags field if present | |
| if len(parts) >= 4: | |
| flags = parts[3] | |
| seenFlags = set() | |
| for flag in flags: | |
| if flag in seenFlags: | |
| raise ImageException("Duplicate flag (%s)" % flag) | |
| if flag not in self.FLAGS: | |
| raise ImageException("Unknown flag (%s)" % flag) | |
| seenFlags.add(flag) | |
| self.is3D = "3" in seenFlags | |
| self.isAlphaScaled = "a" in seenFlags | |
| def get_size(self): | |
| """ | |
| Get the dimensions of this test image, if format is known. | |
| Known cases today where the format is not known: | |
| * 3D .dds files. | |
| * Any .ktx, .hdr, .exr, or .astc file. | |
| Returns: | |
| tuple(int, int): The dimensions of a 2D image, or ``None`` if PIL | |
| could not open the file. | |
| """ | |
| try: | |
| img = PILImage.open(self.filePath) | |
| except IOError: | |
| # HDR files | |
| return None | |
| except NotImplementedError: | |
| # DDS files | |
| return None | |
| return (img.size[0], img.size[1]) | |
| class Image(): | |
| """ | |
| Wrapper around an image on the file system. | |
| """ | |
| # TODO: We don't support KTX yet, as ImageMagick doesn't. | |
| SUPPORTED_LDR = ["bmp", "jpg", "png", "tga"] | |
| SUPPORTED_HDR = ["exr", "hdr"] | |
| def is_format_supported(cls, fileFormat, profile=None): | |
| """ | |
| Test if a given file format is supported by the library. | |
| Args: | |
| fileFormat (str): The file extension (excluding the "."). | |
| profile (str or None): The profile (ldr or hdr) of the image. | |
| Returns: | |
| bool: `True` if the image is supported, `False` otherwise. | |
| """ | |
| assert profile in [None, "ldr", "hdr"] | |
| if profile == "ldr": | |
| return fileFormat in cls.SUPPORTED_LDR | |
| if profile == "hdr": | |
| return fileFormat in cls.SUPPORTED_HDR | |
| return fileFormat in cls.SUPPORTED_LDR or \ | |
| fileFormat in cls.SUPPORTED_HDR | |
| def __init__(self, filePath): | |
| """ | |
| Construct a new Image. | |
| Args: | |
| filePath (str): The path to the image on disk. | |
| """ | |
| self.filePath = filePath | |
| self.proxyPath = None | |
| def get_colors(self, coords): | |
| """ | |
| Get the image colors at the given coordinate. | |
| Args: | |
| coords (tuple or list): A single coordinate, or a list of | |
| coordinates to sample. | |
| Returns: | |
| tuple: A single sample color (if `coords` was a coordinate). | |
| list: A list of sample colors (if `coords` was a list). | |
| Colors are returned as float values between 0.0 and 1.0 for LDR, | |
| and float values which may exceed 1.0 for HDR. | |
| """ | |
| colors = [] | |
| # We accept both a list of positions and a single position; | |
| # canonicalize here so the main processing only handles lists | |
| isList = len(coords) != 0 and isinstance(coords[0], Iterable) | |
| if not isList: | |
| coords = [coords] | |
| for (x, y) in coords: | |
| command = list(CONVERT_BINARY) | |
| command += [self.filePath] | |
| # Ensure convert factors in format origin if needed | |
| command += ["-auto-orient"] | |
| command += [ | |
| "-format", "%%[pixel:p{%u,%u}]" % (x, y), | |
| "info:" | |
| ] | |
| if os.name == 'nt': | |
| command.insert(0, "magick") | |
| result = sp.run(command, stdout=sp.PIPE, stderr=sp.PIPE, | |
| check=True, universal_newlines=True) | |
| rawcolor = result.stdout.strip() | |
| # Decode ImageMagick's annoying named color outputs. Note that this | |
| # only handles "known" cases triggered by our test images, we don't | |
| # support the entire ImageMagick named color table. | |
| if rawcolor == "black": | |
| colors.append([0.0, 0.0, 0.0, 1.0]) | |
| elif rawcolor == "white": | |
| colors.append([1.0, 1.0, 1.0, 1.0]) | |
| elif rawcolor == "red": | |
| colors.append([1.0, 0.0, 0.0, 1.0]) | |
| elif rawcolor == "blue": | |
| colors.append([0.0, 0.0, 1.0, 1.0]) | |
| # Decode ImageMagick's format tuples | |
| elif rawcolor.startswith("srgba"): | |
| rawcolor = rawcolor[6:] | |
| rawcolor = rawcolor[:-1] | |
| channels = rawcolor.split(",") | |
| for i, channel in enumerate(channels): | |
| if (i < 3) and channel.endswith("%"): | |
| channels[i] = float(channel[:-1]) / 100.0 | |
| elif (i < 3) and not channel.endswith("%"): | |
| channels[i] = float(channel) / 255.0 | |
| else: | |
| channels[i] = float(channel) | |
| colors.append(channels) | |
| elif rawcolor.startswith("srgb"): | |
| rawcolor = rawcolor[5:] | |
| rawcolor = rawcolor[:-1] | |
| channels = rawcolor.split(",") | |
| for i, channel in enumerate(channels): | |
| if (i < 3) and channel.endswith("%"): | |
| channels[i] = float(channel[:-1]) / 100.0 | |
| if (i < 3) and not channel.endswith("%"): | |
| channels[i] = float(channel) / 255.0 | |
| channels.append(1.0) | |
| colors.append(channels) | |
| elif rawcolor.startswith("rgba"): | |
| rawcolor = rawcolor[5:] | |
| rawcolor = rawcolor[:-1] | |
| channels = rawcolor.split(",") | |
| for i, channel in enumerate(channels): | |
| if (i < 3) and channel.endswith("%"): | |
| channels[i] = float(channel[:-1]) / 100.0 | |
| elif (i < 3) and not channel.endswith("%"): | |
| channels[i] = float(channel) / 255.0 | |
| else: | |
| channels[i] = float(channel) | |
| colors.append(channels) | |
| elif rawcolor.startswith("rgb"): | |
| rawcolor = rawcolor[4:] | |
| rawcolor = rawcolor[:-1] | |
| channels = rawcolor.split(",") | |
| for i, channel in enumerate(channels): | |
| if (i < 3) and channel.endswith("%"): | |
| channels[i] = float(channel[:-1]) / 100.0 | |
| if (i < 3) and not channel.endswith("%"): | |
| channels[i] = float(channel) / 255.0 | |
| channels.append(1.0) | |
| colors.append(channels) | |
| else: | |
| print(x, y) | |
| print(rawcolor) | |
| assert False | |
| # ImageMagick decodes DDS files as BGRA not RGBA; manually correct | |
| if self.filePath.endswith("dds"): | |
| for color in colors: | |
| tmp = color[0] | |
| color[0] = color[2] | |
| color[2] = tmp | |
| # ImageMagick decodes EXR files with premult alpha; manually correct | |
| if self.filePath.endswith("exr"): | |
| for color in colors: | |
| color[0] /= color[3] | |
| color[1] /= color[3] | |
| color[2] /= color[3] | |
| # Undo list canonicalization if we were given a single scalar coord | |
| if not isList: | |
| return colors[0] | |
| return colors | |