> For the complete documentation index, see [llms.txt](https://cajac.gitbook.io/ctf-notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cajac.gitbook.io/ctf-notes/misc/image-processing/python-image-library.md).

# Python Image Library

Pillow is the friendly PIL (Python Imaging Library) fork.

The Python Imaging Library adds image processing capabilities to your Python interpreter.

This library provides extensive file format support, an efficient internal representation, and fairly powerful image processing capabilities.

The core image library is designed for fast access to data stored in a few basic pixel formats. It should provide a solid foundation for a general image processing tool.

## Extract Encoded Data

### Extract Binary data

Extraction of binary data from the HTB challenge `BitsNBytes`

```python
#!/usr/bin/env python

from PIL import Image

# Open image and read pixel data
image = Image.open('difference.bmp')
width, height = image.size
pixels = image.load()
image.close()

# Convert to binary string
binary_msg = ""
for y in range(0, height):    
    if pixels[0, y] == (0,0,0):
        binary_msg += '0'
    elif pixels[0, y] == (255,255,255):
        binary_msg += '1'
    else:
        binary_msg += 'Error'

# Print the result
print(f"Binary message of lenght: {len(binary_msg)}")
print(binary_msg)

# Divide the binary string into array of 8-bit binary chunks
n = 8
split_result = [binary_msg[i:i+n] for i in range(0, len(binary_msg), n)]

# Convert to ascii text and print it
ascii = ""
for item in split_result:
    ascii += chr(int(str(item), 2))
print(f"ASCII: {ascii}")
```

### Extract LSB-Steganography

Extraction of LSB-steganography from the picoCTF 2025 challenge `RED`

```python
#!/usr/bin/env python

from PIL import Image
from base64 import b64decode

image = Image.open("red.png")
image = image.convert("RGBA")

width, height = image.size

# Read the LSB-bit of each channel in the image for the first row only
bin_array = []
for y in range(1):
    for x in range(width):
        channel = image.getpixel((x, y))
        bin_array.append(str(channel[0] & 1))  # Red
        bin_array.append(str(channel[1] & 1))  # Green
        bin_array.append(str(channel[2] & 1))  # Blue
        bin_array.append(str(channel[3] & 1))  # Alpha

bin_string = "".join(bin_array)

# Divide the binary string into an array of 8-bit binary string chunks
n = 8
split_array = [bin_string[i:i+n] for i in range(0, len(bin_string), n)]

# Convert to ascii text and base64-decode
flag = ""
for item in split_array:
    flag += chr(int(item, 2))
print(b64decode(flag).decode())
```

## Operations on Images

### Add/combine Images

Adding two images from the picoCTF 2021 challenge `Pixelated`

```python
#!/usr/bin/env python

from PIL import Image
from numpy import array

image1 = Image.open('scrambled1.png')
image2 = Image.open('scrambled2.png')

# Convert to arrays
array1 = array(image1)
array2 = array(image2)

# Combine/add the images
result = array1 + array2

# Save the result
Image.fromarray(result).save('flag.png')
print("Result saved as flag.png")
```

## Resources

Pillow - Documentation: <https://pillow.readthedocs.io/en/stable/>

Pillow - Python Imaging Library: <https://pypi.org/project/Pillow/>
