Img2sh
Hello there,
In this post, I want to tell a brief story of how I have created a tool named img2sh. It is also my first python package which is published over PyPI. In this very post, I will try to answer questions like: How is it developed? What are the challenges? How should a package created and deployed over PyPI? Let’s continue!
Img2sh is a tool to show images directly on the terminal. For colored images, 256 xterm color support is required. This script basically resizes the image with anti-aliasing and quantized its colors to xterm color pallette. Github repository of the project can be reached from here
Demo
Testing the package is super easy. Install using pip and run.
|
|
Result:
Interactive mode
|
|
For detailed usage arguments:
|
|
Story
As it can be understood from its name, img2sh is a python app to show images directly in the terminal. I think it could be helpful when connected over ssh to a server with no desktop environment. The images can be examined quickly on the terminal screen. While the tool was developed, the followings are the challenges I have encountered.
Images
In the digital world, images are made of pixels. Pixel is the smallest part of the image which can contain only one color. Color changes with the pixel intensity values. To keep it simple, I added a grayscale image to illustrate the pixel concept. It is a quite low resolution, grayscale image. Pixel values are shown in the following image. Pixel intensity values are changing with how far the pixel value close to black or white.
Colored images basically work with the same concept. The difference is colored images are usually indicated with 3 different pixel values which are red, blue and green. By this method, the proportion of these color intensity is changed to show different colors on screen.
Colors in terminal
How the coloring mechanism works in the terminal should be figured out to implement this app. I understood clearly how colors are handling in an image using the following link. After that, I have found colored python module which provides support for colored terminal output from python apps. I implement the colors using this library.
http://jafrog.com/2013/11/23/colors-in-terminal.html
Parsing command-line arguments
How should the command line arguments be parsed? Actually it is quite easy with python. Let’s examine the next code block:
|
|
After the initialization, arguments can be used with commands like args.width
.
The arguments can be configured as mandatory or optional and the type of
argument also be specified. This package is a pretty useful and standard package
that is widely used most of the python projects.
Image formats
For further improvement in the project, it should be solved how different image formats can handle. Fortunately, Pillow package can handle various kinds of image formats such as jpeg, png, tiff. This packet can provide pixel values for different image types using the same get_pixel method interface. However, the problem is the dimension of the color values are representing. At standard jpeg a pixel value is represented with 24 bits which are 3 bytes. Each byte value represents a different color channels Red, Blue, and Green. Png differs from the alpha channel. At PNG images, colors are created with 4 bytes. Red, Blue, Green, and Alpha. Alpha is the transparency channel of the image. So the dimension of the pixel is different. But this problem is easily solved in findNearestColor function. In these functions, the dimension of the pixel is handled.
Setup.py
In this section, I will try to answer the question that how to create a setup.py file which supports also entry point and can be executed without python shell. Setup.py file is used to define the python package metadata and its installation instructions.
|
|
The entry points of the module can be specified with specifying entry_points property of the object. It is defined as console script and first, the name of the executable should be written. It should be mapped to the executable python function. In my case, it is img2sh:cli:main.
There are useful tricks in the code block also. For example, you do not have to
write a whole long description of this file. It can be read from different files
like README.md
. It is the same for your requirements. It still can be read
from requirements.txt but with one condition. These files should be specified in
the MANIFEST.in file.
MANIFEST.in
|
|
The following link great resource to create a setup.py file. I learned from here. You should check it out. https://python-packaging.readthedocs.io/en/latest/everything.html
Uploading python package
As you may already know, python packages are usually distributed using PyPI
servers. When we use the pip package manager in default, packages are downloaded
from this server. In this project, I want that my package can be installed over
PyPI. So I created a PyPI account and upload my package there.
to Uploading the PyPI package actually quite simple. The following commands are
required to create a package from a module and to upload it to PyPI servers.
|
|
Optimizing performance
How can be the performance of the tool optimized? In the first prototype, the code is written with simple logic. This causes too much processing time because of the for loops inside it. The following code part is written to find the nearest color inside a palette. The function loops in pallette and tries to find the smallest distance. In version 2, I implement it using numpy package. The operation executes in vectorial form and its execution time decreased exponentially. v1
|
|
v2
|
|
|
|
Thank you for your interest. See you later…
Acknowledges
This package is developed using: