Unit 2.2 (Data Compression, Images) Notes
Lab will perform alterations on images, manipulate RGB values, and reduce the number of pixels. College Board requires you to learn about Lossy and Lossless compression.
- Enumerate "Data" Big Idea from College Board
- Image Files and Size
- Python Libraries and Concepts used for Jupyter and Files/Directories
- Reading and Encoding Images (IMPLEMENTATIONS HERE)
- Data Structures, Imperative Programming Style, and Working with Images
- Data Structures and OOP
- My Hacks

Enumerate "Data" Big Idea from College Board
Some of the big ideas and vocab that you observe, talk about it with a partner ...
- "Data compression is the reduction of the number of bits needed to represent data"
- "Data compression is used to save transmission time and storage space."
- "lossy data can reduce data but the original data is not recovered"
- "lossless data lets you restore and recover"
The Image Lab Project contains a plethora of College Board Unit 2 data concepts. Working with Images provides many opportunities for compression and analyzing size.
Image Files and Size
Here are some Images Files. Download these files, load them into
images
directory under _notebooks in your Blog. - Clouds Impression
Describe some of the meta data and considerations when managing Image files. Describe how these relate to Data Compression ...
- File Type, PNG and JPG are two types used in this lab
- Size, height and width, number of pixels
- Visual perception, lossy compression
Python Libraries and Concepts used for Jupyter and Files/Directories
Introduction to displaying images in Jupyter notebook
IPython
Support visualization of data in Jupyter notebooks. Visualization is specific to View, for the web visualization needs to be converted to HTML.
pathlib
File paths are different on Windows versus Mac and Linux. This can cause problems in a project as you work and deploy on different Operating Systems (OS's), pathlib is a solution to this problem.
HACKS:Answering Questions
- What are commands you use in terminal to access files?
Often, we use
cd
and the file path names to enter and exit folders and directories. Sometimes, to see what the exact file path name is, we'll usels
to list the contents of a folder. It's a Bash terminal.
- What are the command you use in Windows terminal to access files?
I'm not a Windows user, but I do know that they also use
cd
but it works slightly differently. They also usedir
instead ofls
andcd
instead ofpwd
.
- What are some of the major differences?
The main difference as far as I know is that Windows runs Bash commands through WSL. File paths also have different prefixes and overall text in Windows because the File Explorer system is different from Mac's Finder.
- Provide what you observed, struggled with, or leaned while playing with this code.
One thing I definitely saw was that image file names are a big deal, particularly when calling specific image paths. The volcano image always caused an error because the code said
jpg
but the image itself is ajpeg
. Another thing I saw was the specific necessary formatting I had to put the image data within to display a specific image with the given functions below. The libraries require some rigid use.
- Why is path a big deal when working with images?
Path is what tells the program where to look for the image in question. If it can't find where to look, the program can't apply effects to it.
- How does the meta data source and label relate to Unit 5 topics?
In Unit 5, we talked about crediting intellectual property to the person/people responsible for it. Addressing image sources when defining them lets us credit the owner fo the intellectual property.
- Look up IPython, describe why this is interesting in Jupyter Notebooks for both Pandas and Images?
IPython is intersting not only because Jupyter Notebooks used to be IPython Notebooks, but because IPython, in a similar vein, provides interactive Python cells like those in notebooks. These cells are an alternative method to display and alter images in Jupyter Notebooks.
IPython and Pandas can be used for such things as analyzing and displaying data sets. WOAH, DATA STRUCTURES...
from IPython.display import Image, display
from pathlib import Path # https://medium.com/@ageitgey/python-3-quick-tip-the-easy-way-to-deal-with-file-paths-on-windows-mac-and-linux-11a072b58d5f
# prepares a series of images
def image_data(path=Path("images/"), images=None): # path of static images is defaulted
if images is None: # default image
images = [
{'source': "Peter Carolin", 'label': "Clouds Impression", 'file': "clouds-impression.png"},
{'source': "Peter Carolin", 'label': "Lassen Volcano", 'file': "lassen-volcano.jpeg"}
]
for image in images:
# File to open
image['filename'] = path / image['file'] # file with path
return images
def image_display(images):
for image in images:
display(Image(filename=image['filename']))
# Run this as standalone tester to see sample data printed in Jupyter terminal
if __name__ == "__main__":
# print parameter supplied image
green_square = image_data(images=[{'source': "Internet", 'label': "Green Square", 'file': "green-square-16.png"}])
image_display(green_square)
# display default images from image_data()
default_images = image_data()
image_display(default_images)
# BONUS: printing smiley face
smiley_face = image_data(images=[{'source': "VectorStock", 'label': "Awesome Smiley", 'file': "awesomesmiley.jpeg"}])
image_display(smiley_face)
Reading and Encoding Images (IMPLEMENTATIONS HERE)
PIL (Python Image Library)
Pillow or PIL provides the ability to work with images in Python. Geeks for Geeks shows some ideas on working with images.
PIL Implementation
See all of the stuff in the hacks later. (Click here)
base64
Image formats (JPG, PNG) are often called Binary File formats, it is difficult to pass these over HTTP. Thus, base64 converts binary encoded data (8-bit, ASCII/Unicode) into a text encoded scheme (24 bits, 6-bit Base64 digits). Thus base64 is used to transport and embed binary images into textual assets such as HTML and CSS.
- How is Base64 similar or different to Binary and Hexadecimal?
- Translate first 3 letters of your name to Base64.
base64 Implementation
Base64 is similar to binary and hexadecimal in that it works in specific amounts of bits that hold just enough information for their purposes. While binary has advantages at being a simple form of storing information, Base64 helps to store more complicated data.
First three letters of my name: "Dre" (capitalized)
First three letters in Base64: ("RHJl")
First three letters of my name: "dre" (not capitalized)
First three letters in Base64: ("ZHJl")
numpy
Numpy is described as "The fundamental package for scientific computing with Python". In the Image Lab, a Numpy array is created from the image data in order to simplify access and change to the RGB values of the pixels, converting pixels to grey scale.
io, BytesIO
Input and Output (I/O) is a fundamental of all Computer Programming. Input/output (I/O) buffering is a technique used to optimize I/O operations. In large quantities of data, how many frames of input the server currently has queued is the buffer. In this example, there is a very large picture that lags.
io, BytesIO Implementation
- Where have you been a consumer of buffering?
Buffering is something scattered all over the internet. I most often experience it when watching YouTube or Netflix, since videos require a lot of frames of image data to be loaded over the internet. Many websites have this problem as well:I often find myself waiting for images to load in even on sites like College Board.
- From your consumer experience, what effects have you experienced from buffering?
Buffering really primarily affects my decision to use a site or program or not. I can't think of any specific website as an example, but I have often stopped consistently playing certain video games because of load times. For example, I used to really enjoy playing Animal Crossing: New Horizons during COVID, but it wasn't optimized well enough for the Switch console and ended up buffering for more than a whole minute every time I tried to boot up the game.
Buffering can also be helpful for the functionality of a program in my experience. For example, most video games use an "input buffering" system to let an early button press function even after the press is over. This makes the experience more fluid.
- How do these effects apply to images?
Since images are made up of a lot of data (since they are a complex visual form of media), the process of loading an image may be taxing and what information is being pulled and read may be buffered, resulting in lag like we see on many sites.
Data Structures, Imperative Programming Style, and Working with Images
Introduction to creating meta data and manipulating images. Look at each procedure and explain the the purpose and results of this program. Add any insights or challenges as you explored this program.
Interacting:Questions
- Does this code seem like a series of steps are being performed?
Yes, because they really are.
- Describe Grey Scale algorithm in English or Pseudo code.
Below, NumPy is used to convert an image to grayscale. This works by taking the average of the three RGB values, then setting each of them as the average. This works because, on the RGB scale, if all three of the RGB values are equal, then they combine to make a shade of gray. If they are all 255, it is black; if they are all 0, it is white.
A special case is put in place for if the image is a PNG. PNG images are special because they are rendered in the RGBA scale, not just RGB. This doesn't affect the color scale, however; the A value is kept the same while the RGB values are set as the average after the process.
- Describe scale image. What is before and after on pixels in three images?
All of the images below are displayed with a width of 320 pixels, with height adjusted according to the width-height ratio. Before this filtration, the image is displayed with its width and height dictated by the actual resolution of the image, possibly with some slight restrictions from the CSS styling of this blog. Afterward, the width is always set to 320px, and the height is changed according to the initial height-width ratio.
- Is scale image a type of compression? If so, does it line it up with College Board terms described?
Typically, image scaling is not considered a type of data compression, since it doesn't reduce the amount of data required to represent an image. Instead, image scaling involves changing the size of an image by either increasing or decreasing its resolution.
from IPython.display import HTML, display
from pathlib import Path # https://medium.com/@ageitgey/python-3-quick-tip-the-easy-way-to-deal-with-file-paths-on-windows-mac-and-linux-11a072b58d5f
from PIL import Image as pilImage # as pilImage is used to avoid conflicts
from io import BytesIO
import base64
import numpy as np
# prepares a series of images
def image_data(path=Path("images/"), images=None): # path of static images is defaulted
if images is None: # default image
images = [
{'source': "Internet", 'label': "Green Square", 'file': "green-square-16.png"},
{'source': "Peter Carolin", 'label': "Clouds Impression", 'file': "clouds-impression.png"},
{'source': "Peter Carolin", 'label': "Lassen Volcano", 'file': "lassen-volcano.jpeg"},
{'source': "VectorStock", 'label': "Awesome Smiley", 'file': "awesomesmiley.jpeg"}
]
for image in images:
# File to open
image['filename'] = path / image['file'] # file with path
return images
# Large image scaled to baseWidth of 320
def scale_image(img):
baseWidth = 320
scalePercent = (baseWidth/float(img.size[0]))
scaleHeight = int((float(img.size[1])*float(scalePercent)))
scale = (baseWidth, scaleHeight)
return img.resize(scale)
# PIL image converted to base64
def image_to_base64(img, format):
with BytesIO() as buffer:
img.save(buffer, format)
return base64.b64encode(buffer.getvalue()).decode()
# Set Properties of Image, Scale, and convert to Base64
def image_management(image): # path of static images is defaulted
# Image open return PIL image object
img = pilImage.open(image['filename'])
# Python Image Library operations
image['format'] = img.format
image['mode'] = img.mode
image['size'] = img.size
# Scale the Image
img = scale_image(img)
image['pil'] = img
image['scaled_size'] = img.size
# Scaled HTML
image['html'] = '<img src="data:image/png;base64,%s">' % image_to_base64(image['pil'], image['format'])
# Create Grey Scale Base64 representation of Image
def image_management_add_html_grey(image):
# Image open return PIL image object
img = image['pil']
format = image['format']
img_data = img.getdata() # Reference https://www.geeksforgeeks.org/python-pil-image-getdata/
image['data'] = np.array(img_data) # PIL image to numpy array
image['gray_data'] = [] # key/value for data converted to gray scale
# 'data' is a list of RGB data, the list is traversed and hex and binary lists are calculated and formatted
for pixel in image['data']:
# create gray scale of image, ref: https://www.geeksforgeeks.org/convert-a-numpy-array-to-an-image/
average = (pixel[0] + pixel[1] + pixel[2]) // 3 # average pixel values and use // for integer division
if len(pixel) > 3:
image['gray_data'].append((average, average, average, pixel[3])) # PNG format
else:
image['gray_data'].append((average, average, average))
# end for loop for pixels
img.putdata(image['gray_data'])
image['html_grey'] = '<img src="data:image/png;base64,%s">' % image_to_base64(img, format)
# Jupyter Notebook Visualization of Images
if __name__ == "__main__":
# Use numpy to concatenate two arrays
images = image_data()
# Display meta data, scaled view, and grey scale for each image
for image in images:
image_management(image)
print("---- meta data -----")
print(image['label'])
print(image['source'])
print(image['format'])
print(image['mode'])
print("Original size: ", image['size'])
print("Scaled size: ", image['scaled_size'])
print("-- original image --")
display(HTML(image['html']))
print("--- grey image ----")
image_management_add_html_grey(image)
display(HTML(image['html_grey']))
print()
Data Structures and OOP
Most data structures classes require Object Oriented Programming (OOP). Since this class is lined up with a College Course, OOP will be talked about often. Functionality in remainder of this Blog is the same as the prior implementation. Highlight some of the key difference you see between imperative and oop styles.
- Read imperative and object-oriented programming on Wikipedia
- Consider how data is organized in two examples, in relations to procedures
- Look at Parameters in Imperative and Self in OOP
Additionally, review all the imports in these three demos. Create a definition of their purpose, specifically these ...
- PIL
- numpy
- base64
from IPython.display import HTML, display
from pathlib import Path # https://medium.com/@ageitgey/python-3-quick-tip-the-easy-way-to-deal-with-file-paths-on-windows-mac-and-linux-11a072b58d5f
from PIL import Image as pilImage # as pilImage is used to avoid conflicts
from io import BytesIO
import base64
import numpy as np
class Image_Data:
def __init__(self, source, label, file, path, baseWidth=320):
self._source = source # variables with self prefix become part of the object,
self._label = label
self._file = file
self._filename = path / file # file with path
self._baseWidth = baseWidth
# Open image and scale to needs
self._img = pilImage.open(self._filename)
self._format = self._img.format
self._mode = self._img.mode
self._originalSize = self.img.size
self.scale_image()
self._html = self.image_to_html(self._img)
self._html_grey = self.image_to_html_grey()
@property
def source(self):
return self._source
@property
def label(self):
return self._label
@property
def file(self):
return self._file
@property
def filename(self):
return self._filename
@property
def img(self):
return self._img
@property
def format(self):
return self._format
@property
def mode(self):
return self._mode
@property
def originalSize(self):
return self._originalSize
@property
def size(self):
return self._img.size
@property
def html(self):
return self._html
@property
def html_grey(self):
return self._html_grey
# Large image scaled to baseWidth of 320
def scale_image(self):
scalePercent = (self._baseWidth/float(self._img.size[0]))
scaleHeight = int((float(self._img.size[1])*float(scalePercent)))
scale = (self._baseWidth, scaleHeight)
self._img = self._img.resize(scale)
# PIL image converted to base64
def image_to_html(self, img):
with BytesIO() as buffer:
img.save(buffer, self._format)
return '<img src="data:image/png;base64,%s">' % base64.b64encode(buffer.getvalue()).decode()
# Create Grey Scale Base64 representation of Image
def image_to_html_grey(self):
img_grey = self._img
numpy = np.array(self._img.getdata()) # PIL image to numpy array
grey_data = [] # key/value for data converted to gray scale
# 'data' is a list of RGB data, the list is traversed and hex and binary lists are calculated and formatted
for pixel in numpy:
# create gray scale of image, ref: https://www.geeksforgeeks.org/convert-a-numpy-array-to-an-image/
average = (pixel[0] + pixel[1] + pixel[2]) // 3 # average pixel values and use // for integer division
if len(pixel) > 3:
grey_data.append((average, average, average, pixel[3])) # PNG format
else:
grey_data.append((average, average, average))
# end for loop for pixels
img_grey.putdata(grey_data)
return self.image_to_html(img_grey)
# prepares a series of images, provides expectation for required contents
def image_data(path=Path("images/"), images=None): # path of static images is defaulted
if images is None: # default image
images = [
{'source': "Internet", 'label': "Green Square", 'file': "green-square-16.png"},
{'source': "Peter Carolin", 'label': "Clouds Impression", 'file': "clouds-impression.png"},
{'source': "Peter Carolin", 'label': "Lassen Volcano", 'file': "lassen-volcano.jpeg"}
]
return path, images
# turns data into objects
def image_objects():
id_Objects = []
path, images = image_data()
for image in images:
id_Objects.append(Image_Data(source=image['source'],
label=image['label'],
file=image['file'],
path=path,
))
return id_Objects
# Jupyter Notebook Visualization of Images
if __name__ == "__main__":
for ido in image_objects(): # ido is an Imaged Data Object
print("---- meta data -----")
print(ido.label)
print(ido.source)
print(ido.file)
print(ido.format)
print(ido.mode)
print("Original size: ", ido.originalSize)
print("Scaled size: ", ido.size)
print("-- scaled image --")
display(HTML(ido.html))
print("--- grey image ---")
display(HTML(ido.html_grey))
print()
My Hacks
These are my hacks. I made sure to respond to every hack mentioned in this section of the template.
Early Seed award
Check out the awesome smiley face added throughout the file. He is BEGGING you to give me a seed point.
AP Prep
- In the Blog add notes and observations on each code cell that request an answer.
I made sure to answer all unanswered questions throughout this note template. I added additional code comments to help understand the code being used, especially with the code above.
- In this blog, add College Board practice problems for 2.2
See below...
College Board Practice Quiz
Here are the results from the 2.2 practice quiz.

All of the questions in this quiz were pretty self-explanatory and common sense.
2.2 College Board Practice Problems
Back when I finished my first draft of this blog and the hacks, I didn't realize that this section was referring to a College Board quiz; I thought we had to make our own practice questions. I did so below.
Q1. What is true about lossy compression and lossless compression?
- Lossy compression involves losing time by perfectly recreating the original file.
- Lossless compression involves creating a user report of any errors found in the file.
- Lossy compression involves discarding non-necessary information to decrease file size, while lossless compression just eliminates redundant data.
- Lossless compression is always preferable to lossy data because lossy data can create serious discrepancies between the original and the compressed version.
Q2. What is sequencing?
- A logic structure in which instructions are executed one at a time, in order.
- A method of programming which requires instructions to be connected to each other with distinct numerical instructions.
- A logic structure in which the most time-consuming functions are executed first and the least time-consuming last.
- A method of asynchronous programming used by large teams to connect separate strings of code for efficient collaboration.
One Lossy Image and One Lossless Image
- Choose 2 images, one that will more likely result in lossy data compression and one that is more likely to result in lossless data compression. Explain.
This image should be lossily compressed...

...while this image should likely be losslessly compressed. (Though it looks like it has already been lossily compressed before.)

Which kind of compression is based on many factors including file type. Typically, PNGs use lossless compression, and less is lost in simpler images. JPEG images trend toward lossier compression, especially with complex designs.
Ultimately, if an image is very simple, it would more likely be lossily compressed, since nothing of importance will be lost.
When it comes to non-images, videos are often more lossily compressed because the image data takes up a lot of space and individual frames being compressed may not come off as too obvious. Usually files in .zip or .7z format are losslessly compressed, while things such as MPEG and MP3 files are more often lossily compressed.
Project Addition
- If your project has images in it, try to implement an image change that has a purpose. (Ex. An item that has been sold out could become gray scale)
This is the one I haven't done, since my part of the project doesn't use images. It is all HTML elements and CSS styling.
Custom PIL Use
- Numpy, manipulating pixels. As opposed to Grey Scale treatment, pick a couple of other types like red scale, green scale, or blue scale. We want you to be manipulating pixels in the image.
I did redscale, bluescale, and greenscale below, along with a weird RGB scale that I was curious about.
Redscale, Bluescale, and Greenscale Filters
See the code below for redscale, bluescale, and greenscale filters.
from IPython.display import HTML, display
from pathlib import Path # https://medium.com/@ageitgey/python-3-quick-tip-the-easy-way-to-deal-with-file-paths-on-windows-mac-and-linux-11a072b58d5f
from PIL import Image as pilImage # as pilImage is used to avoid conflicts
from io import BytesIO
import base64
import numpy as np
# prepares a series of images
def image_data(path=Path("images/"), images=None): # path of static images is defaulted
if images is None: # default image
images = [
{'source': "Peter Carolin", 'label': "Clouds Impression", 'file': "clouds-impression.png"},
{'source': "VectorStock", 'label': "Awesome Smiley", 'file': "awesomesmiley.jpeg"}
]
for image in images:
# File to open
image['filename'] = path / image['file'] # file with path
return images
# Large image scaled to baseWidth of 320
def scale_image(img):
baseWidth = 320
scalePercent = (baseWidth/float(img.size[0]))
scaleHeight = int((float(img.size[1])*float(scalePercent)))
scale = (baseWidth, scaleHeight)
return img.resize(scale)
# PIL image converted to base64
def image_to_base64(img, format):
with BytesIO() as buffer:
img.save(buffer, format)
return base64.b64encode(buffer.getvalue()).decode()
# Set Properties of Image, Scale, and convert to Base64
def image_management(image): # path of static images is defaulted
# Image open return PIL image object
img = pilImage.open(image['filename'])
# Python Image Library operations
image['format'] = img.format
image['mode'] = img.mode
image['size'] = img.size
# Scale the Image
img = scale_image(img)
image['pil'] = img
image['scaled_size'] = img.size
# Scaled HTML
image['html'] = '<img src="data:image/png;base64,%s">' % image_to_base64(image['pil'], image['format'])
# Create redscale Base64 image version
def image_management_add_html_red(image):
# Image open return PIL image object
img = image['pil']
format = image['format']
img_data = img.getdata() # Reference https://www.geeksforgeeks.org/python-pil-image-getdata/
image['data'] = np.array(img_data) # PIL image to numpy array
image['red_data'] = [] # key/value for data converted to red scale
# 'data' is a list of RGB data, the list is traversed and hex and binary lists are calculated and formatted
for pixel in image['data']:
# create red scale of image
redval = pixel[0] # only preserving the red val
if len(pixel) > 3:
image['red_data'].append((redval, 0, 0, pixel[3])) # PNG format
else:
image['red_data'].append((redval, 0, 0))
# end for loop for pixels
img.putdata(image['red_data'])
image['html_red'] = '<img src="data:image/png;base64,%s">' % image_to_base64(img, format)
# Create greenscale Base64 image version
def image_management_add_html_green(image):
# Image open return PIL image object
img = image['pil']
format = image['format']
img_data = img.getdata() # Reference https://www.geeksforgeeks.org/python-pil-image-getdata/
image['data'] = np.array(img_data) # PIL image to numpy array
image['green_data'] = [] # key/value for data converted to red scale
# 'data' is a list of RGB data, the list is traversed and hex and binary lists are calculated and formatted
for pixel in image['data']:
# create green scale of image
greenval = pixel[1] # only preserving the green val
if len(pixel) > 3:
image['green_data'].append((0, greenval, 0, pixel[3])) # PNG format
else:
image['green_data'].append((0, greenval, 0))
# end for loop for pixels
img.putdata(image['green_data'])
image['html_green'] = '<img src="data:image/png;base64,%s">' % image_to_base64(img, format)
# Create bluescale Base64 image version
def image_management_add_html_blue(image):
# Image open return PIL image object
img = image['pil']
format = image['format']
img_data = img.getdata() # Reference https://www.geeksforgeeks.org/python-pil-image-getdata/
image['data'] = np.array(img_data) # PIL image to numpy array
image['blue_data'] = [] # key/value for data converted to red scale
# 'data' is a list of RGB data, the list is traversed and hex and binary lists are calculated and formatted
for pixel in image['data']:
# create blue scale of image
blueval = pixel[2] # only preserving the blue val
if len(pixel) > 3:
image['blue_data'].append((0, 0, blueval, pixel[3])) # PNG format
else:
image['blue_data'].append((0, 0, blueval))
# end for loop for pixels
img.putdata(image['blue_data'])
image['html_blue'] = '<img src="data:image/png;base64,%s">' % image_to_base64(img, format)
# Jupyter Notebook Visualization of Images
if __name__ == "__main__":
# Use numpy to concatenate two arrays
images = image_data()
# Display meta data, scaled view, and grey scale for each image
for image in images:
redcopy = image
greencopy = image
bluecopy = image
image_management(image)
print("-- original image --")
display(HTML(image['html']))
print("--- red image ----")
image_management(redcopy)
image_management_add_html_red(redcopy)
display(HTML(redcopy['html_red']))
print("--- green image ----")
image_management(greencopy)
image_management_add_html_green(greencopy)
display(HTML(greencopy['html_green']))
print("--- blue image ----")
image_management(bluecopy)
image_management_add_html_blue(bluecopy)
display(HTML(bluecopy['html_blue']))
print()
And just out of curiosity, I tried a filter that only filtered out green values. I figured it would make it look weird since the greenscale version looked the most normal.
from IPython.display import HTML, display
from pathlib import Path # https://medium.com/@ageitgey/python-3-quick-tip-the-easy-way-to-deal-with-file-paths-on-windows-mac-and-linux-11a072b58d5f
from PIL import Image as pilImage # as pilImage is used to avoid conflicts
from io import BytesIO
import base64
import numpy as np
# prepares a series of images
def image_data(path=Path("images/"), images=None): # path of static images is defaulted
if images is None: # default image
images = [
{'source': "VectorStock", 'label': "Awesome Smiley", 'file': "awesomesmiley.jpeg"}
]
for image in images:
# File to open
image['filename'] = path / image['file'] # file with path
return images
# Large image scaled to baseWidth of 320
def scale_image(img):
baseWidth = 320
scalePercent = (baseWidth/float(img.size[0]))
scaleHeight = int((float(img.size[1])*float(scalePercent)))
scale = (baseWidth, scaleHeight)
return img.resize(scale)
# PIL image converted to base64
def image_to_base64(img, format):
with BytesIO() as buffer:
img.save(buffer, format)
return base64.b64encode(buffer.getvalue()).decode()
# Set Properties of Image, Scale, and convert to Base64
def image_management(image): # path of static images is defaulted
# Image open return PIL image object
img = pilImage.open(image['filename'])
# Python Image Library operations
image['format'] = img.format
image['mode'] = img.mode
image['size'] = img.size
# Scale the Image
img = scale_image(img)
image['pil'] = img
image['scaled_size'] = img.size
# Scaled HTML
image['html'] = '<img src="data:image/png;base64,%s">' % image_to_base64(image['pil'], image['format'])
# Create redscale Base64 image version
def image_management_add_html_weird(image):
# Image open return PIL image object
img = image['pil']
format = image['format']
img_data = img.getdata() # Reference https://www.geeksforgeeks.org/python-pil-image-getdata/
image['data'] = np.array(img_data) # PIL image to numpy array
image['weird_data'] = [] # key/value for data converted to the weird scale
# 'data' is a list of RGB data, the list is traversed and hex and binary lists are calculated and formatted
for pixel in image['data']:
# create red scale of image
redval = pixel[0] # preserving the red val
blueval = pixel[2] # and preserving the blue val
if len(pixel) > 3:
image['weird_data'].append((redval, 0, blueval, pixel[3])) # PNG format
else:
image['weird_data'].append((redval, 0, blueval))
# end for loop for pixels
img.putdata(image['weird_data'])
image['html_weird'] = '<img src="data:image/png;base64,%s">' % image_to_base64(img, format)
# Jupyter Notebook Visualization of Images
if __name__ == "__main__":
# Use numpy to concatenate two arrays
images = image_data()
# Display meta data, scaled view, and grey scale for each image
for image in images:
image_management(image)
print("-- original image --")
display(HTML(image['html']))
print("--- weird image ----")
image_management_add_html_weird(image)
display(HTML(image['html_weird']))
print()
from PIL import Image, ImageDraw, ImageFont
# get an image
with Image.open("images/awesomesmiley.jpeg").convert("RGBA") as base:
# make a blank image for the text, initialized to transparent text color
txt = Image.new("RGBA", base.size, (255, 255, 255, 0))
# get a drawing context
d = ImageDraw.Draw(txt)
# draw text, full opacity
d.text((10, 100), "There is text on my smiley face!", fill=(255, 255, 255, 255))
out = Image.alpha_composite(base, txt)
display(out)
I used the default font because other fonts were giving me issues and I didn't want to have to import a .ttf
file myself.