Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save sadielbartholomew/a393c483eaef0d37ade8dbc7a2207707 to your computer and use it in GitHub Desktop.
Save sadielbartholomew/a393c483eaef0d37ade8dbc7a2207707 to your computer and use it in GitHub Desktop.
Generate spreadsheet (Excel) pixel art from an arbitrary image
"""Gist to generate spreadsheet (Excel) pixel art from an arbitrary image.
Gist by Sadie Louise Bartholomew ('sadielbartholomew'), 05.08.21.
Q) Why would I want to do this?
A) Exactly. Programming gives us too much power to do silly and pointless
things.
Requires certain libraries to work: see the `import` list.
Initial example creates a new '.xlsx' file with one tab with the Bernie
Sanders 'Mittens' meme, pixels formed by reducing the image in size by a
factor of 10 and then applying 'fill' values of the appropriate colour on
cells that have been made (roughly) square in shape.
A different, arbitrary, image can instead be applied as pixel art by
changing the URL in `URL_OF_IMAGE_TO_USE` to point to the desired image, or
by adapting the code minimally to instead apply an image taken from the
local filesystem, if preferred. The pixelation can also be adapated simply,
by changing the `REDUCE_SIZE_BY` factor. Note that a full-size image (i.e.
`REDUCE_SIZE_BY = 1` is entirely possible, but zooming out to view it in
full on the final spreadsheet might be difficult.
"""
import matplotlib.colors # no alias to distinguish from openpyxl.styles.colors
import numpy as np
import openpyxl
import tempfile
from PIL import Image
from urllib.request import urlretrieve
# 1. Define parameters (adapt these as you wish to customise the pixel art)
URL_OF_IMAGE_TO_USE = (
"https://static01.nyt.com/images/"
"2021/01/22/world/21xp-sanders-meme/21xp-sanders-meme-superJumbo-v4.jpg"
)
REDUCE_SIZE_BY = 10
CELL_SIDE_LENGTH = 60.0
SAVE_SPREADSHEET_AS = "excel_pixel_art.xlsx"
# 2. Create a new '.xlsx' spreadsheet object
# Note: it won't exist as a file until the object is saved (`.save` method)
workbook = openpyxl.Workbook()
worksheet = workbook.active
# 3. Make the cells of the active (and only) tab, to hold the pixel art, square
# NOTE: openpyxl column width units depend on the width of the default font
# and since this may vary from environment to environment, the cells may not
# become square for you with this, so either adapt the divisor below until
# they become roughly square, else edit the width of the cells manually
# once the spreadsheet is generated with the pixel art. (If the cells are
# not square, the pixel art will have the wrong length-to-width proportion.)
worksheet.sheet_format.defaultColWidth = CELL_SIDE_LENGTH / 6.66
worksheet.sheet_format.defaultRowHeight = CELL_SIDE_LENGTH
# 4. Retrieve the image to create the pixel art from its online location
tempfile_for_image = tempfile.NamedTemporaryFile()
urlretrieve(URL_OF_IMAGE_TO_USE, tempfile_for_image.name)
# 5. Read-in the image from its temp. file as a PIL object
image = Image.open(tempfile_for_image)
# 6. Reduce the image object by the desired size and convert it to an array
image = image.reduce(REDUCE_SIZE_BY)
image_array = np.asarray(image)
# 7. Now iterate over the rows and columns, creating pixels of the image:
for row in range(image_array.shape[0]):
for col in range(image_array.shape[1]):
# 7i) Match the spreadsheet cell to the corresponding pixel of the
# image by indexing the appropriate part of the image array
pixel = image_array[row, col]
# 7ii) Convert the RGB tuple to the colour format used by openpyxl
rgb_tuple = pixel[:3]
hexa = matplotlib.colors.rgb2hex(
[1.0 * clr / 255 for clr in rgb_tuple])
colour = openpyxl.styles.colors.Color(rgb=f"FF{hexa.lstrip('#')}")
# 7iii) Write the corresponding array value as a fill colour
# to form an effective image pixel on the spreadsheet
print(f"Setting the image pixel at {row + 2, col + 2} in {hexa}")
worksheet.cell(
row=row + 2, column=col + 2).fill = openpyxl.styles.PatternFill(
fill_type="solid", fgColor=colour
)
# 8. Finally, save the constructed spreadsheet holding our pixel art
workbook.save(SAVE_SPREADSHEET_AS)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment