Captcha image generator
Tags: python, webdev, tutorial, pillow
Published: 2020-10-07 17:29:14

We will build a logic to create some random captcha image using python with the help of pillow package.

**[For more detailed reference about pillow check this.](https://pillow.readthedocs.io/en/stable/handbook/tutorial.html#using-the-image-class)**

install this package using this command
```
   pip install pillow
```
## [To learn more about virtual environment](https://dev.to/magesh236/setup-python-virtual-environment-2ad8)

## Create new image
this piece of code will create a white image with 90X60 and saved a blank_image.png
```python
   from PIL import Image
   img = Image.new('RGB', (90, 60), color = 'white')
   img.save('blank_image.png')
```
blank_image.png
![blank_image.png](https://dev-to-uploads.s3.amazonaws.com/i/1xhsc3xm7c2aarz4lxze.png)

## Draw text on image
now we created a image and saved it, lets add some text to it
```python
   from PIL import Image, ImageDraw
   draw = ImageDraw.Draw(img)
   draw.text((20,20), "Hello", fill=(38, 38, 38))
   img.save('blank_image.png')
```

`Hello` is written in img object at poin 10X10
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/p1vp58c98oheuuvihc34.png)

## Draw lines
Let draw some line on the image
```python
   draw.line((40,30, 150,300), fill=120, width=1)
   draw.line((20,30, 30,20), fill=88, width=2)
```
fill is the color and you set the width size,
(40,30) is the starting point for line 1 and ends at (150,300).
You can notice that the end point is larger than the image size, it will be omitted.

Same as line 1, line 2 starts at (20,30) and ends in (30,20)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/plmu7qbra76sl556sv8s.png)

## Draw points
Let add some more stuff
pass points as [python tuples of tuples](https://www.programdoc.com/python/tuples) to draw points in the image 
```python
   draw.point(((30, 40), (10, 20), (14, 25), (35, 10), (14, 28), (17, 25)), fill="black")
```
this one will throws the dot points in the image at the given XY coordinates.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/o6ut7ui8ee7ffybxwkqo.png)

## Generate the captcha string
This same logic is used in Url Shortener, you can check it here
### [Build Url Shortener API In Django - Redis](https://dev.to/magesh236/build-url-shortener-api-in-django-redis-gj8)
random_string function generate a random string of length 5, you can adjust it.
```python
import string, random 

# generate thr random captcha string
def random_string():
    # hash length
    N = 5
    s = string.ascii_uppercase + string.ascii_lowercase + string.digits
    # generate a random string of length 5
    random_string = ''.join(random.choices(s, k=N))
    return random_string
```

## [Python lambda function](https://www.programdoc.com/python/lambda)
**what is lambda?**
   Is a special function with one line, and with one expression. It can get multiple  arguments.
```python
# Normal funtion
def square(a):
    return a*a

square(5) ---> 25

# lambda funtion
square = lambda a: a*a
square(5) ---> 25
```

lambda function to get the random location in the image
```python
   # lambda function - used to pick a random loaction in image
getit = lambda : (random.randrange(5, 85),random.randrange(5, 55))
```

this will spite out the random value between 5 and 84,
Note: 85 not taken
```python
   random.randrange(5, 85)
```

values for colors which will be randomly picked
```python
   # pick a random colors for points
   colors = ["black","red","blue","green",(64, 107, 76),(0, 87, 128),(0, 3, 82)]
   fill_color = [120,145,130,89,58,50,75,86,98,176,]
   # pick a random colors for lines
   fill_color = [(64, 107, 76),(0, 87, 128),(0, 3, 82),(191, 0, 255),(72, 189, 0),(189, 107, 0),(189, 41, 0)]
```

To get a random value from list, this will get a random color value one
```python
   random.choice(colors)
```

#### Full logic to generate the captcha image
```python
from PIL import Image, ImageDraw, ImageFont
import string, random 

# generate thr random captcha string
def random_string():
    # hash length
    N = 5
    s = string.ascii_uppercase + string.ascii_lowercase + string.digits
    # generate a random string of length 5
    random_string = ''.join(random.choices(s, k=N))
    return random_string

# lambda function - used to pick a random loaction in image
getit = lambda : (random.randrange(5, 85),random.randrange(5, 55))

# pick a random colors for points
colors = ["black","red","blue","green",(64, 107, 76),(0, 87, 128),(0, 3, 82)]

# fill_color = [120,145,130,89,58,50,75,86,98,176,]
# pick a random colors for lines
fill_color = [(64, 107, 76),(0, 87, 128),(0, 3, 82),(191, 0, 255),(72, 189, 0),(189, 107, 0),(189, 41, 0)]

# generate thr random captcha string
def random_string():
    # hash length
    N = 5
    s = string.ascii_uppercase + string.ascii_lowercase + string.digits
    # generate a random string of length 5
    random_string = ''.join(random.choices(s, k=N))
    return random_string

# generate the captcha image
def gen_captcha_img():
    # create a img object
    img = Image.new('RGB', (90, 60), color="white")
    draw = ImageDraw.Draw(img)
    
    # get the random string
    captcha_str = random_string()
    # get the text color
    text_colors = random.choice(colors)
    font_name = "fonts/SansitaSwashed-VariableFont_wght.ttf"
    font = ImageFont.truetype(font_name, 18)
    draw.text((20,20), captcha_str, fill=text_colors, font=font)
    
    # draw some random lines
    for i in range(5,random.randrange(6, 10)):
        draw.line((getit(), getit()), fill=random.choice(fill_color), width=random.randrange(1,3))

    # draw some random points
    for i in range(10,random.randrange(11, 20)):
        draw.point((getit(), getit(), getit(), getit(), getit(), getit(), getit(), getit(), getit(), getit()), fill=random.choice(colors))
    
    # save image in captcha_img directory
    img.save("captcha_img/"+ captcha_str +".png")
    
    return True
```
![Alt Text](https://media.giphy.com/media/tNSdR34g4jy1i/giphy.gif)

                              **WE MADE IT** 🥳🥳🥳

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qibgplxxt8qnlju3di9i.png)

You will notice the  code `for i in range(5,random.randrange(6, 10)):` which is used to randomise the line and points in each new image.
font used in this is from [google fonts](https://fonts.google.com/)
https://fonts.google.com/specimen/Sansita+Swashed

**Note:** To validate the value(Backend) in the string you can store the string in the session or you can use your own way.
**To generate more detailed image used some small images with different shapes in it and throws it randomly.**

## More articles
#### [Build Url Shortener API In Django - Redis](https://dev.to/magesh236/build-url-shortener-api-in-django-redis-gj8)
#### [Scrape IMDB movie rating and details using python](https://dev.to/magesh236/scrape-imdb-movie-rating-and-details-3a7c)
#### [Build a News app using django - App like google news](https://dev.to/magesh236/news-app-in-django-2dcd)
#### [Django News App Deployment On Heroku](https://dev.to/magesh236/django-news-app-deployment-on-heroku-2k9o)



## Thanks you, have a great day ahead.🤪😎