Assignment Chef icon Assignment Chef
All English tutorials

Programming lesson

Mastering Run-Length Encoding in Python: A Hands-On Tutorial for Image Compression

Learn run-length encoding (RLE) in Python through a practical image compression project. Covers encoding/decoding, hex conversion, and menu-driven programs with real-world examples.

run-length encoding Python RLE image compression Python COP3502C homework 3 Python RLE tutorial encode decode RLE Python hex string conversion Python list manipulation Python Python loops and lists lossless compression Python pixel art compression Python menu driven program RLE encoding example Python data compression project Python string to data RLE decoding algorithm

Introduction to Run-Length Encoding (RLE)

Run-length encoding (RLE) is a simple form of lossless data compression that's widely used in image processing, especially for pixel art and simple graphics. In this tutorial, you'll learn how to implement RLE in Python as part of a homework assignment (like COP3502C HW 3 and 4). You'll build functions to encode and decode raw pixel data, convert between data and strings, and create a menu-driven program. By the end, you'll have a solid understanding of loops, lists, string manipulation, and type casting in Python.

RLE works by replacing consecutive identical values (runs) with a count and the value. For example, the flat data [15, 15, 15, 4, 4, 4, 4, 4, 4] becomes [3, 15, 6, 4] in RLE. This technique is used in everything from retro video games to modern AI image compression.

Understanding the Assignment

Your task is to implement several functions that handle RLE encoding and decoding. You'll also create a standalone program with a menu that lets users load data (from files, test images, or user input) and display it in various formats. The project simulates real-world image compression workflows.

Key Functions to Implement

  • to_hex_string(data): Converts a list of integers (0-15) to a hexadecimal string without delimiters. Example: [3, 15, 6, 4]"3f64".
  • count_runs(flat_data): Counts the number of runs in flat data. Example: [15,15,15,4,4,4,4,4,4]2.
  • encode_rle(flat_data): Encodes flat data into RLE format. Example: [15,15,15,4,4,4,4,4,4][3,15,6,4].
  • get_decoded_length(rle_data): Returns the length of the decoded data from RLE. Example: [3,15,6,4]9.
  • decode_rle(rle_data): Decodes RLE data back to flat data. Example: [3,15,6,4][15,15,15,4,4,4,4,4,4].
  • string_to_data(data_string): Converts a hex string to a list of integers. Example: "3f64"[3,15,6,4].
  • to_rle_string(rle_data): Converts RLE data to a human-readable string with colons. Example: [15,15,6,4]"15f:64".
  • string_to_rle(rle_string): Inverse of the above. Example: "15f:64"[15,15,6,4].

Step-by-Step Implementation

1. to_hex_string

This function takes a list of integers (each 0-15) and returns a hexadecimal string. Use Python's hex() or a custom mapping. For example, 15 becomes 'f'.

def to_hex_string(data):
    return ''.join(hex(val)[2:] for val in data)

2. count_runs

Iterate through the flat data and count how many times the value changes.

def count_runs(flat_data):
    if not flat_data:
        return 0
    runs = 1
    for i in range(1, len(flat_data)):
        if flat_data[i] != flat_data[i-1]:
            runs += 1
    return runs

3. encode_rle

Build the RLE list by counting consecutive identical values.

def encode_rle(flat_data):
    if not flat_data:
        return []
    rle = []
    count = 1
    for i in range(1, len(flat_data)):
        if flat_data[i] == flat_data[i-1]:
            count += 1
        else:
            rle.append(count)
            rle.append(flat_data[i-1])
            count = 1
    rle.append(count)
    rle.append(flat_data[-1])
    return rle

4. get_decoded_length

Sum the counts (every other element starting from index 0).

def get_decoded_length(rle_data):
    return sum(rle_data[i] for i in range(0, len(rle_data), 2))

5. decode_rle

Expand each run into the flat list.

def decode_rle(rle_data):
    flat = []
    for i in range(0, len(rle_data), 2):
        count = rle_data[i]
        value = rle_data[i+1]
        flat.extend([value] * count)
    return flat

6. string_to_data

Convert each hex character to an integer.

def string_to_data(data_string):
    return [int(ch, 16) for ch in data_string]

7. to_rle_string

Format each run as count in decimal and value in hex, separated by colons.

def to_rle_string(rle_data):
    parts = []
    for i in range(0, len(rle_data), 2):
        parts.append(f"{rle_data[i]}{hex(rle_data[i+1])[2:]}")
    return ':'.join(parts)

8. string_to_rle

Parse the colon-separated string back to RLE list.

def string_to_rle(rle_string):
    rle = []
    for part in rle_string.split(':'):
        count = int(part[:-1])
        value = int(part[-1], 16)
        rle.append(count)
        rle.append(value)
    return rle

Building the Menu-Driven Program

Your main() function should display a welcome message, show a color test, then present a menu with options to load data and display results. Use a loop to keep the program running until the user chooses to exit. Here's a skeleton:

def main():
    print("Welcome to RLE Image Processor!")
    ConsoleGfx.test_rainbow()
    image_data = None
    while True:
        print_menu()
        choice = input("Select a Menu Option: ")
        if choice == '1':
            filename = input("Enter name of file to load: ")
            image_data = ConsoleGfx.load_file(filename)
        elif choice == '6':
            if image_data:
                ConsoleGfx.display_image(image_data)
            else:
                print("No image data loaded.")
        # ... other options
        elif choice == '0':
            break

Real-World Applications and Trends

RLE isn't just for homework—it's used in modern technologies. For instance, AI image generators often use compression techniques like RLE to reduce file sizes when training on pixel art datasets. In gaming, retro-style indie games use RLE to store sprite data efficiently. Even in finance, RLE can be applied to compress time-series data where values repeat. As of 2026, with the rise of edge AI and IoT devices, lightweight compression algorithms like RLE are becoming essential for real-time data transmission.

"RLE is a foundational concept that bridges simple programming exercises and real-world data compression."

Testing Your Implementation

Test each function with the provided examples. For instance:

print(to_hex_string([3, 15, 6, 4]))  # Expected: "3f64"
print(count_runs([15,15,15,4,4,4,4,4,4]))  # Expected: 2
print(encode_rle([15,15,15,4,4,4,4,4,4]))  # Expected: [3,15,6,4]
print(get_decoded_length([3,15,6,4]))  # Expected: 9
print(decode_rle([3,15,6,4]))  # Expected: [15,15,15,4,4,4,4,4,4]
print(string_to_data("3f64"))  # Expected: [3,15,6,4]
print(to_rle_string([15,15,6,4]))  # Expected: "15f:64"
print(string_to_rle("15f:64"))  # Expected: [15,15,6,4]

Common Pitfalls

  • Forgetting that RLE data always has an even number of elements (count, value pairs).
  • Mixing up decimal and hexadecimal representations: counts are decimal, values are hex.
  • Not handling empty input gracefully.
  • Off-by-one errors in loops.

Conclusion

By completing this tutorial, you've built a complete RLE image compression toolkit in Python. You've practiced essential programming concepts like loops, lists, string formatting, and modular design. These skills are directly applicable to more advanced topics in data compression, image processing, and even AI. As you move forward, consider exploring how RLE compares to other compression methods like Huffman coding or LZW. Happy coding!