Build yourself an ugly little jumper... with the power of Python!
Tags: python, webdev, pillow
Published: 2020-12-02 10:02:58

This post is part of the [Anvil Advent calendar](https://anvil.works/advent). We're building one web app a day for 24 days, [using nothing but Python](https://anvil.works/articles/python-gui-builder-web)! This is day 1, and we're kicking off with some funky image manipulation.

# Wrap up warm

Today we're making ugly Christmas jumpers with the power of Python.

![](https://anvil.works/advent/img/ugly-jumpers/reindeer-jumper.jpg)

Try it out here! 

<h3><center><a href="https://christmas-jumper-generator.anvil.app">https://christmas-jumper-generator.anvil.app</a></center></h3>

Just head to the app and start uploading images to see what they'll look like once we've mangled them into something you could put on a Christmas jumper.

# How is it done?

Once you've uploaded an image in your browser, the app sends it over to the client where we do some fun things to it in [Pillow](https://pillow.readthedocs.io/en/stable/index.html). It's really easy to convert an AnvilMedia object to a Pillow object and vice versa, with the help of [BytesIO](https://docs.python.org/3/library/io.html#io.BytesIO):

```python
from io import BytesIO
from Pillow import Image

def convert_blob_to_image(image_file_from_client):
  """Take an AvilMedia object from the client and turn it into a Pillow Image object."""
  image = Image.open(BytesIO(image_file_from_client.get_bytes()))
  image = image.convert("RGB") # make sure we're using the right colour mode for what we want to do
  return image

def convert_image_to_blob(image):
  """Prepare a Pillow Image object to be sent back to the client by turning into an Avil BlobMedia."""
  with BytesIO() as buf:
    image.save(buf, format='PNG') # you could also use 'JPEG' here if you wished
    blob = anvil.BlobMedia('image/png', buf.getvalue())
  return blob
```

Once we've got a Pillow [Image instance](https://pillow.readthedocs.io/en/stable/reference/Image.html), we're free to do all kinds of weird and wonderful things with it.

The algorithm in the app works like this: 

 * resizes the image to 50 pixels wide using `Image.resize`
 * quantizes the colours in the image so that there are only a limited number using `Image.convert` and specifying `colors = 7` (a number I found to be a happy, ugly medium between 'too busy' and 'unrecognisably few')
 * replaces each colour in the image with a suitably Christmassy shade, using `Image.getpixel` and `Image.putpixel`. It also makes sure that the top left corner pixel, which is most likely to be some kind of background to the uploaded image, gets coloured in with the same shade as the background Christmas jumper, so it looks seamless.
 * enlarges the image, keeping the 'pixellated' look with a `resample = Image.NEAREST` parameter to the `Image.resize` method
 * slaps it onto the background image of the red Christmas jumper using `Image.paste`.

If you want to see the code in more detail, you can clone the app for yourself and see the server code in all its glory!

<h3><a href="https://anvil.works/build#clone:OWVZBAXAIVLGFTOH%3dQYR6R54IPJMYIHEA4JAQAUPD">Open in Anvil >></a></h3>

---

## What's Next?

If you thought this was cool, check out the rest of Anvil!

Head to the [Anvil Learning Centre](https://anvil.works/learn/tutorials) for more tutorials, or head to our [examples page](https://anvil.works/learn/examples) to see how to build some complex apps in Anvil.

<h3><a href="https://anvil.works/learn">More Anvil Tutorials >></a></h3>