From 3704cb71acf630aae4054b15b9e594e29b74652f Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 30 Nov 2024 12:15:44 -0500 Subject: [PATCH] improved argument validation, fleshed README out, and began adding support for CMYK --- README.md | 29 ++++++++++++-- color-converter.py | 94 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 107 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 535f425..dc26c17 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,33 @@ # color-converter -A python utility that translates color codes to other formats. +A CLI utility written in Python that translates color codes to other formats. = actively under construction = # Usage -Download the python file and run it! No dependencies besides vanilla Python. +Download the python file and run it! Requires nothing besides vanilla Python :) -I'll flesh README out later, but for now, use the help menu: +I'll flesh 'usage' README out later, but for now, use the help menu: `python color-converter.py --help` + +# Project Goals +I started this project because I found myself converting between Hex and RGB a lot while ricing my Arch setup and I started thinking about the available color tools. Using any random color-picker site (or the ones baked into search engines) to go from RBG->Hex (and vice versa) work plenty fine, but I started to wonder if there was a simple way to do said conversions locally. Something that was super quick, doesn't require internet, and doesn't have any fluff. I poked around on the AUR for any sort of CLI color code converting utility, and couldn't find anything. At this point, I had the realization that I had no idea how color codes work, and that it could be a fun way to learn something new by making one myself. + +Also, up til this point, I had no personal projects written in Python (which is a language I'm trying to learn quickly for my job), and I had always wanted to write a legit CLI tool. So, how about 4 birds in one stone? + + +# Roadmap +I originally (and still) just want this to be an exercise in Python that results in a somewhat useful tool. I would like to get it to a level of polish where I'm proud to release it with the MIT license or something and have it on the AUR. + +That said, as I develop this, I see lots of room for improvement. Such as: +- automatic format detection, no longer requiring a flag to indicate what format input is +- accept more than one color code at a time +- (to expand on ^) accept input from text file, where each line is it's own color code to convert +- add flags to control which conversions are output (in the case you only want a single conversion) and how (do you want just the raw values or the whole string for with commas and stuff?) +- combine the last two bullet points and boom: now the tool could take a whole list of colors in X format and spit out a file where every color is in Y format +- (to expand on ^) if we had automatic format detection and formatting output flags, you could pass in a whole file of any color formats and standardize them to a given format. + + +maybe these ideas branch off into separate projects themselves, but: +- accept images as output and print out the average color (of all pixels) in any format +- TUI color picker??? maybe look into the interface platforms that ncspot uses for mouse input +- accept images as output and some sort of color code that gets applied to said image (like a CLI program for applying color filters to images) diff --git a/color-converter.py b/color-converter.py index 0dfae00..a574bd1 100644 --- a/color-converter.py +++ b/color-converter.py @@ -1,27 +1,40 @@ -import sys +# import sys import argparse -TYPES = ['hex', 'rgb', 'hsl', 'cmyk'] +# Order of types must match order of arguments defined +# (or else arg validation will no longer work properly) +TYPES = ['hex', 'rgb', 'cmyk'] +# look into CMY, HSL, HSV + HEX_LETTERS = ['a', 'b', 'c', 'd', 'e', 'f'] def main(): + + # Set up arguments parser = argparse.ArgumentParser() - parser.add_argument('--hex', action='store_true', help='convert from hex (accepted formats: [ffffff] or ["#ffffff"])') - parser.add_argument('--rgb', action='store_true', help='convert from RGB (accepted formats: [R G B], [\"rgb(R, G, B)\"], and [\"rgb(R,G,B)\"])') - parser.add_argument('color', nargs='*', help='accepts a color in Hex, RGB, CYMK, or HSL and performs format conversions') + + parser.add_argument('-hex', action='store_true', help='convert from hex (accepts hexadecimal input [ffffff] or string ["#ffffff"] (both are case insensitive)') + parser.add_argument('-rgb', action='store_true', help='convert from RGB (accepts integer input [R G B], or string [\"rgb(R, G, B)\"] (case/whitespace insensitive)') + parser.add_argument('-cmyk', action='store_true', help='convert from CMYK (accepts integer input [C M Y K], or string [\"cmyk(C, M, Y, K)\"] (case/whitespace insensitive)') + + parser.add_argument('color', nargs='*', help='accepts a color in Hex, RGB, CMYK, or HSL and performs format conversions (does not support CMYK profiles, conversions are uncalibrated)') args = parser.parse_args() + + # debug print + print('args type: ', type(vars(args))) print(args, '\n') - color = args.color - - if len(color) == 0 : - print('ERROR: Must enter color code') - return + # INPUT SYNTAX VALIDATION + if not validateArguments(args) : + return; + + color = args.color + # HANDLE HEX INPUT if args.hex : - color = color[0].strip('#') + color = color[0].lower().strip('#') if not validateHex(color) : return @@ -31,7 +44,7 @@ def main(): if args.rgb : # cleanse any non-numerical stuff if len(color) == 1 : - color = color[0].strip('rgb(').strip(')').split(',') + color = color[0].lower().strip('rgb(').strip(')').split(',') if not validateRGB(color) : return @@ -39,7 +52,16 @@ def main(): color[i] = int(color[i]) convertFromRGB(color) - + + # HANDLE CMYK INPUT + if args.cmyk : + # cleanse any non-numerical stuff besides '%' + if len(color) == 1 : + color = color[0].lower().strip('cmyk(').strip(')').split(',') + if not validateCMYK(color) : + return + + print('convert cmyk: ', color) ## # HEX CONVERSION SECTION ## @@ -86,6 +108,9 @@ def convertToRGB(codeFormat, code) : tempSum = 0 print('RGB: ', rgbValue) + + + ## # INPUT VALIDATION SECTION ## @@ -124,6 +149,49 @@ def validateRGB(values) : return False return True +# Takes in a string. Returns True if valid CMYK values. +def validateCMYK(values) : + if len(values) != 4 : + print('ERROR: Improper number of values (should be 4)') + return False + + for value in values : + if not value.strip().strip('%').isnumeric() : + print('ERROR: Improper format for CMYK value(s). All values must be numeric and between 0-100(%)!') + return False + value = int(value) + if (value < 0) or (value > 100) : + print('ERROR: Each CMYK value must be between 0-100(%)') + return False + + return True + + + +## +# GENERAL UTILITIES +## + +# Takes in the program's arguments generated by argparse. Returns True if valid arguments +def validateArguments(args) : + # First, check that only one input flag is being used + flagsActive = 0 + for flag in range(len(vars(args))-1) : + # this uses our TYPES list to key into the args dictionary and determine how many flags are True + if vars(args)[TYPES[flag]] : + flagsActive += 1 + if flagsActive > 1 : + print('ERROR: Currently this tool only supports one input type at a time. Too many flags!') + return False + + # Second, check that there is a color code to convert + if len(color) == 0 : + print('ERROR: Must enter both an input flag and color code (did you forget to wrap color code in quotes?)\nFor more info, use the \'-h\' or \'--help\' flag.') + return False + + return True + + # Takes in a decimal number and converts it to hexadecimal def hex(number) : number = int(number)