Image to ASCII converter website using Python and Flask

11 December, 2020
2 minute read

Pic2ASCII

This, along with insertcoin was also made as a college project. This one was made in collaboration with my classmate, Shubham Bhagwat.

The Project

The project was called “Pic2ASCII”. Self-explanatory title, it would just convert any image that you upload into an ASCII-fied image or text. The PlayStation logo below is an example: pslogo_conversion.png

Conversion Logic

Our repo was forked from this repository.

Input

A few things in the python files were changed, such as the way the program receives parameters. The program initally took arguments like so:

img2img.py --input rockstar.png --output output/rockstar.png --mode simple

It was not possible to execute this program as such in a web application. So, I changed the way we had to call the program by directly calling the main function and adding the necessary parameters.

Before img2img_param_before.png

After img2img_param_before.png

This sorted out the programs’ input.

Output

Image to ASCII-fied Text

The Tempfile Python library creates temporary files and directories that can be used for a short time. They get deleted and cleaned up soon afterward.

IMPORTANT: If using such an library in a web application, you should change the default storage directory of the temporary files because they get stored in the system’s temp folder by default.

In my case on Windows, it chose the C:\Temp folder. It can be changed to the tmp/ folder in the project’s root by adding this line in the program:

tempfile.tempdir = "tmp"

Once this is done, the temporary file can be created and used like so:

img2txt.py

# create and open the temporary file in text mode
temp = tempfile.TemporaryFile(mode='w+t')

# write to the file
for i in range(num_rows):
    for j in range(num_cols):
        temp.writelines(CHAR_LIST[min(
            int(
                np.mean(image[
                    int(i * cell_height):min(int((i + 1) *
                                                    cell_height), height),
                    int(j * cell_width):min(int((j + 1) *
                                                cell_width), width)]) *
                num_chars / 255), num_chars - 1)])
    temp.writelines("\n")

# set the file pointer at the beginning of the file
temp.seek(0)
return temp.read(), errors

The value returned is a tuple with the file itself and the errors encountered(if any).

Uploading the converted text to Paste.ee

This was done using this Python module for Paste.ee, a free pastebin.

As the converted text was returned as a string, all that was left to do was to use the pastee module’s Paste() function to upload the text.

main.py

# upload the converted text to paste.ee
paste = Paste(outputtxt, private=False, desc=inlink, views=10)

# raw and download links
raw_link = paste['raw']
dl_link = paste['download']

# Reduce the size of the preview text so that it doesn't overflow
font_size = 0.4 * (int(request.form.get('num_cols')) / 125)

Image to ASCII-fied Image

The changes here are relatively small. The original program saved the converted image file to the specified output location.

The file saving code was replaced to save the converted image contents to a buffer, instead of a file itself. This was made possible with the BytesIO module.

BytesIO can be used in the place of an actual file object while not being a file itself. Any data written to it actually goes to an in-memory buffer.

The image is written to and returned as follows:

img2img.py

# Create the image and write to it
out_image = Image.new("L", (out_width, out_height), bg_code)
draw = ImageDraw.Draw(out_image)
for i in range(num_rows):
    line = "".join([
        CHAR_LIST[min(
            int(
                np.mean(image[
                    int(i * cell_height):min(int(
                        (i + 1) * cell_height), height),
                    int(j * cell_width):min(int(
                        (j + 1) * cell_width), width)]) * num_chars / 255),
            num_chars - 1)] for j in range(num_cols)
    ]) + "\n"
    draw.text((0, i * char_height), line, fill=255 - bg_code, font=font)

if background == "white":
    cropped_image = ImageOps.invert(out_image).getbbox()
else:
    cropped_image = out_image.getbbox()

out_image = out_image.crop(cropped_image)

# Save the image to the BytesIO buffer
output = BytesIO()
out_image.save(output, format('JPEG'))

# return the contents of the buffer
outimg_data = output.getvalue()
return outimg_data, errors

Uploading the Image to Imgur

This was done using the PyImgur Python module. The library’s functions made it easy to upload the converted image to store in Imgur.

Firstly, to upload any file to Imgur, we had to:

Authorization with the Imgur API was done in a similar manner to the previous post in which we authorized our application with MongoDB. We add the API key as an environment variable (say IMGUR_KEY), and connect using

im = pyimgur.Imgur(os.environ.get("IMGUR_KEY"))

After this, uploading is done using the send_request() function:

out = im._send_request('https://api.imgur.com/3/image',
                                       method='POST',
                                       params={'image': outputimg})

where outputimg is the ASCII-fied image encoded using b64encode().

The front-end of the ASCII generator was thus complete!

You can check out the web app here.

The rest of the code is in my Github repository, ASCII-generator.


Previous post
Next post