Created
August 5, 2021 19:28
-
-
Save sadielbartholomew/a393c483eaef0d37ade8dbc7a2207707 to your computer and use it in GitHub Desktop.
Generate spreadsheet (Excel) pixel art from an arbitrary image
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""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