1cc1dc7a3Sopenharmony_ci#!/usr/bin/env python3 2cc1dc7a3Sopenharmony_ci# SPDX-License-Identifier: Apache-2.0 3cc1dc7a3Sopenharmony_ci# ----------------------------------------------------------------------------- 4cc1dc7a3Sopenharmony_ci# Copyright 2020 Arm Limited 5cc1dc7a3Sopenharmony_ci# 6cc1dc7a3Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); you may not 7cc1dc7a3Sopenharmony_ci# use this file except in compliance with the License. You may obtain a copy 8cc1dc7a3Sopenharmony_ci# of the License at: 9cc1dc7a3Sopenharmony_ci# 10cc1dc7a3Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 11cc1dc7a3Sopenharmony_ci# 12cc1dc7a3Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software 13cc1dc7a3Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 14cc1dc7a3Sopenharmony_ci# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 15cc1dc7a3Sopenharmony_ci# License for the specific language governing permissions and limitations 16cc1dc7a3Sopenharmony_ci# under the License. 17cc1dc7a3Sopenharmony_ci# ----------------------------------------------------------------------------- 18cc1dc7a3Sopenharmony_ci""" 19cc1dc7a3Sopenharmony_ciThe ``astc_image_info`` utility provides basic image query capabilities. It is 20cc1dc7a3Sopenharmony_cia modal command line utility, exposing multiple available operators. 21cc1dc7a3Sopenharmony_ci 22cc1dc7a3Sopenharmony_ci* ``info``: Query structural information about the image, such as image 23cc1dc7a3Sopenharmony_ci dimensions, number of color channels, and the min/max of each channel. 24cc1dc7a3Sopenharmony_ci* ``color``: Query the stored color value at a specific pixel coordinate, and 25cc1dc7a3Sopenharmony_ci print the result in a variety of different formats. 26cc1dc7a3Sopenharmony_ci 27cc1dc7a3Sopenharmony_ciBoth modes allow multiple images to be specified on the command line. 28cc1dc7a3Sopenharmony_ci""" 29cc1dc7a3Sopenharmony_ci 30cc1dc7a3Sopenharmony_ciimport argparse 31cc1dc7a3Sopenharmony_ciimport sys 32cc1dc7a3Sopenharmony_ci 33cc1dc7a3Sopenharmony_cifrom PIL import Image 34cc1dc7a3Sopenharmony_ci 35cc1dc7a3Sopenharmony_ci 36cc1dc7a3Sopenharmony_cidef main_color(args): 37cc1dc7a3Sopenharmony_ci """ 38cc1dc7a3Sopenharmony_ci Main function for the "color" mode. 39cc1dc7a3Sopenharmony_ci 40cc1dc7a3Sopenharmony_ci This mode prints the color at a specific pixel coordinate in each image. 41cc1dc7a3Sopenharmony_ci The color value is printed in a variety of color formats (decimal, HTML 42cc1dc7a3Sopenharmony_ci string, float). 43cc1dc7a3Sopenharmony_ci 44cc1dc7a3Sopenharmony_ci Args: 45cc1dc7a3Sopenharmony_ci args (Namespace): The parsed command line arguments. 46cc1dc7a3Sopenharmony_ci 47cc1dc7a3Sopenharmony_ci Returns: 48cc1dc7a3Sopenharmony_ci int: The process return code. 49cc1dc7a3Sopenharmony_ci """ 50cc1dc7a3Sopenharmony_ci retCode = 0 51cc1dc7a3Sopenharmony_ci 52cc1dc7a3Sopenharmony_ci for i, image in enumerate(args.images): 53cc1dc7a3Sopenharmony_ci if i != 0: 54cc1dc7a3Sopenharmony_ci print("") 55cc1dc7a3Sopenharmony_ci 56cc1dc7a3Sopenharmony_ci img = Image.open(image.name) 57cc1dc7a3Sopenharmony_ci x = args.location[0] 58cc1dc7a3Sopenharmony_ci y = args.location[1] 59cc1dc7a3Sopenharmony_ci 60cc1dc7a3Sopenharmony_ci print(image.name) 61cc1dc7a3Sopenharmony_ci print("=" * len(image.name)) 62cc1dc7a3Sopenharmony_ci 63cc1dc7a3Sopenharmony_ci if (x >= img.size[0]) or (y >= img.size[1]): 64cc1dc7a3Sopenharmony_ci print("- ERROR: location out-of-bounds [%ux%u]" % img.size) 65cc1dc7a3Sopenharmony_ci retCode = 1 66cc1dc7a3Sopenharmony_ci else: 67cc1dc7a3Sopenharmony_ci color = img.getpixel((x, y)) 68cc1dc7a3Sopenharmony_ci 69cc1dc7a3Sopenharmony_ci # Print byte values 70cc1dc7a3Sopenharmony_ci print("+ Byte: %s" % str(color)) 71cc1dc7a3Sopenharmony_ci 72cc1dc7a3Sopenharmony_ci # Print hex values 73cc1dc7a3Sopenharmony_ci fmtString = "+ Hex: #" + ("%02X" * len(color)) 74cc1dc7a3Sopenharmony_ci print(fmtString % color) 75cc1dc7a3Sopenharmony_ci 76cc1dc7a3Sopenharmony_ci # Print float values 77cc1dc7a3Sopenharmony_ci parts = ["%g"] * len(color) 78cc1dc7a3Sopenharmony_ci parts = ", ".join(parts) 79cc1dc7a3Sopenharmony_ci fmtString = "+ Float: (" + parts + ")" 80cc1dc7a3Sopenharmony_ci print(fmtString % tuple(float(x)/255.0 for x in color)) 81cc1dc7a3Sopenharmony_ci 82cc1dc7a3Sopenharmony_ci return retCode 83cc1dc7a3Sopenharmony_ci 84cc1dc7a3Sopenharmony_ci 85cc1dc7a3Sopenharmony_cidef main_info(args): 86cc1dc7a3Sopenharmony_ci """ 87cc1dc7a3Sopenharmony_ci Main function for the "info" mode. 88cc1dc7a3Sopenharmony_ci 89cc1dc7a3Sopenharmony_ci This mode prints the basic metadata of an image: 90cc1dc7a3Sopenharmony_ci 91cc1dc7a3Sopenharmony_ci - the overall image size. 92cc1dc7a3Sopenharmony_ci - the number of color channels. 93cc1dc7a3Sopenharmony_ci - the min/max value in each color channel. 94cc1dc7a3Sopenharmony_ci 95cc1dc7a3Sopenharmony_ci Args: 96cc1dc7a3Sopenharmony_ci args (Namespace): The parsed command line arguments. 97cc1dc7a3Sopenharmony_ci 98cc1dc7a3Sopenharmony_ci Returns: 99cc1dc7a3Sopenharmony_ci int: The process return code. 100cc1dc7a3Sopenharmony_ci """ 101cc1dc7a3Sopenharmony_ci for i, image in enumerate(args.images): 102cc1dc7a3Sopenharmony_ci if i != 0: 103cc1dc7a3Sopenharmony_ci print("") 104cc1dc7a3Sopenharmony_ci 105cc1dc7a3Sopenharmony_ci img = Image.open(image.name) 106cc1dc7a3Sopenharmony_ci minmax = img.getextrema() 107cc1dc7a3Sopenharmony_ci 108cc1dc7a3Sopenharmony_ci print(image.name) 109cc1dc7a3Sopenharmony_ci print("=" * len(image.name)) 110cc1dc7a3Sopenharmony_ci print("+ Size: %ux%u" % (img.size[0], img.size[1])) 111cc1dc7a3Sopenharmony_ci print("+ Channels: %s" % ("".join(img.getbands()))) 112cc1dc7a3Sopenharmony_ci for j, channel in enumerate(img.getbands()): 113cc1dc7a3Sopenharmony_ci print(" + %s: %u - %u" % (channel, *minmax[j])) 114cc1dc7a3Sopenharmony_ci 115cc1dc7a3Sopenharmony_ci return 0 116cc1dc7a3Sopenharmony_ci 117cc1dc7a3Sopenharmony_ci 118cc1dc7a3Sopenharmony_cidef parse_loc(value): 119cc1dc7a3Sopenharmony_ci """ 120cc1dc7a3Sopenharmony_ci Command line argument parser for position arguments. 121cc1dc7a3Sopenharmony_ci 122cc1dc7a3Sopenharmony_ci Args: 123cc1dc7a3Sopenharmony_ci value (str): The command line argument string to parse. Must be of the 124cc1dc7a3Sopenharmony_ci form <int>x<int>", where both integers must be zero or positive. 125cc1dc7a3Sopenharmony_ci 126cc1dc7a3Sopenharmony_ci Returns: 127cc1dc7a3Sopenharmony_ci list(int, int): The parsed location. 128cc1dc7a3Sopenharmony_ci 129cc1dc7a3Sopenharmony_ci Raises: 130cc1dc7a3Sopenharmony_ci ArgumentTypeError: The value is not a valid location. 131cc1dc7a3Sopenharmony_ci """ 132cc1dc7a3Sopenharmony_ci error = argparse.ArgumentTypeError("%s is an invalid location" % value) 133cc1dc7a3Sopenharmony_ci svalue = value.split("x") 134cc1dc7a3Sopenharmony_ci 135cc1dc7a3Sopenharmony_ci if len(svalue) != 2: 136cc1dc7a3Sopenharmony_ci raise error 137cc1dc7a3Sopenharmony_ci 138cc1dc7a3Sopenharmony_ci try: 139cc1dc7a3Sopenharmony_ci ivalue = [int(x) for x in svalue if int(x) >= 0] 140cc1dc7a3Sopenharmony_ci except ValueError: 141cc1dc7a3Sopenharmony_ci raise error 142cc1dc7a3Sopenharmony_ci 143cc1dc7a3Sopenharmony_ci if len(ivalue) != len(svalue): 144cc1dc7a3Sopenharmony_ci raise error 145cc1dc7a3Sopenharmony_ci 146cc1dc7a3Sopenharmony_ci return ivalue 147cc1dc7a3Sopenharmony_ci 148cc1dc7a3Sopenharmony_ci 149cc1dc7a3Sopenharmony_cidef parse_command_line(): 150cc1dc7a3Sopenharmony_ci """ 151cc1dc7a3Sopenharmony_ci Parse the command line. 152cc1dc7a3Sopenharmony_ci 153cc1dc7a3Sopenharmony_ci Returns: 154cc1dc7a3Sopenharmony_ci Namespace: The parsed command line container. 155cc1dc7a3Sopenharmony_ci """ 156cc1dc7a3Sopenharmony_ci parser = argparse.ArgumentParser() 157cc1dc7a3Sopenharmony_ci subparsers = parser.add_subparsers( 158cc1dc7a3Sopenharmony_ci title="Operations") 159cc1dc7a3Sopenharmony_ci 160cc1dc7a3Sopenharmony_ci # Create the parser for the "pipette" command 161cc1dc7a3Sopenharmony_ci parserA = subparsers.add_parser( 162cc1dc7a3Sopenharmony_ci "color", 163cc1dc7a3Sopenharmony_ci help="Print color at given coordinate") 164cc1dc7a3Sopenharmony_ci 165cc1dc7a3Sopenharmony_ci parserA.set_defaults(func=main_color) 166cc1dc7a3Sopenharmony_ci 167cc1dc7a3Sopenharmony_ci parserA.add_argument( 168cc1dc7a3Sopenharmony_ci "location", metavar="loc", type=parse_loc, 169cc1dc7a3Sopenharmony_ci help="The location spec XxY") 170cc1dc7a3Sopenharmony_ci 171cc1dc7a3Sopenharmony_ci parserA.add_argument( 172cc1dc7a3Sopenharmony_ci "images", metavar="image", nargs="+", type=argparse.FileType("r"), 173cc1dc7a3Sopenharmony_ci help="The images to query") 174cc1dc7a3Sopenharmony_ci 175cc1dc7a3Sopenharmony_ci # Create the parser for the "size" command 176cc1dc7a3Sopenharmony_ci parserB = subparsers.add_parser( 177cc1dc7a3Sopenharmony_ci "info", 178cc1dc7a3Sopenharmony_ci help="Print image metadata info") 179cc1dc7a3Sopenharmony_ci 180cc1dc7a3Sopenharmony_ci parserB.set_defaults(func=main_info) 181cc1dc7a3Sopenharmony_ci 182cc1dc7a3Sopenharmony_ci parserB.add_argument( 183cc1dc7a3Sopenharmony_ci "images", metavar="image", nargs="+", type=argparse.FileType("r"), 184cc1dc7a3Sopenharmony_ci help="The images to query") 185cc1dc7a3Sopenharmony_ci 186cc1dc7a3Sopenharmony_ci # Cope with the user failing to specify any sub-command. Note on Python 3.8 187cc1dc7a3Sopenharmony_ci # we could use required=True on the add_subparsers call, but we cannot do 188cc1dc7a3Sopenharmony_ci # this on 3.6 which is our current min-spec. 189cc1dc7a3Sopenharmony_ci args = parser.parse_args() 190cc1dc7a3Sopenharmony_ci if not hasattr(args, "func"): 191cc1dc7a3Sopenharmony_ci parser.print_help() 192cc1dc7a3Sopenharmony_ci return None 193cc1dc7a3Sopenharmony_ci 194cc1dc7a3Sopenharmony_ci return args 195cc1dc7a3Sopenharmony_ci 196cc1dc7a3Sopenharmony_ci 197cc1dc7a3Sopenharmony_cidef main(): 198cc1dc7a3Sopenharmony_ci """ 199cc1dc7a3Sopenharmony_ci The main function. 200cc1dc7a3Sopenharmony_ci 201cc1dc7a3Sopenharmony_ci Returns: 202cc1dc7a3Sopenharmony_ci int: The process return code. 203cc1dc7a3Sopenharmony_ci """ 204cc1dc7a3Sopenharmony_ci args = parse_command_line() 205cc1dc7a3Sopenharmony_ci if args: 206cc1dc7a3Sopenharmony_ci return args.func(args) 207cc1dc7a3Sopenharmony_ci 208cc1dc7a3Sopenharmony_ci return 0 209cc1dc7a3Sopenharmony_ci 210cc1dc7a3Sopenharmony_ci 211cc1dc7a3Sopenharmony_ciif __name__ == "__main__": 212cc1dc7a3Sopenharmony_ci sys.exit(main()) 213