How does bit-wise operation work for encrypting grayscale images? How does bit-wise operation work for encrypting grayscale images?

In my Khan Academy course they encrypt an image with bitwise_and, bitwise_or and bitwise_xor. I have tried, without success, to replicate their results.

The Khan Academy write-up: https://www.khanacademy.org/computing/computer-science/cryptography/ciphers/a/xor-and-the-one-time-pad

My results: https://imgur.com/a/ltvj5os

The way I did the operation is this (Python code):

def get_bitwise_image(image, key, op):

    and_image = []
    row=0
    col=0
    while row &lt; len(image):
        new_row = []
        col = 0
        while col &lt; len(image[row]):
            # a bitwise and between say 243 and 1 is bitwise and between 2 intergers and not binaries. So, their constituent bits and and-ed together
            # ex: 1 =&gt; 00000001 and 243 =&gt; 11110011
            # 00000001
            # 11110011
            # --------
            # 00000001 =&gt; 1
            if op == 'and':
                new_row.append(image[row, col] &amp; key[row, col])
            elif op == 'or':
                new_row.append(image[row, col] | key[row, col])
            else:
                new_row.append(image[row, col] ^ key[row, col])
            col += 1
        and_image.append(new_row)
        row+=1
    return and_image


My second image is grayscale with values 0-255, and my key is a matrix of the same dimensions as an image with random 1s and 0s.

Key is defined as: key = numpy.random.randint(0, 2, image.shape)

Why is the Khan Academy's result completely different from mine? How are grayscale images encrypted with bit-wise operations?
I have solved it.

The main reason was that I'm supposed to use LOGICAL operations instead of BITWISE operations.

The new results: https://imgur.com/a/NLa5Q8J

my function:

def logical_xor(message, key, op):
    message = np.asarray(message)
    key = np.asarray(key)
    new_image = []
    row=0
    col=0
    while row &lt; len(message):
        new_row = []
        col = 0
        while col &lt; len(message[row]):
            if op == 'and':
                new_row.append(message[row, col] and key[row, col]) # and instead of &amp;
            elif op == 'or':
                new_row.append(message[row, col] or key[row, col])
            else:
                new_row.append(message[row, col] !=  key[row, col]) # xor
            col += 1
        new_image.append(new_row)
        row+=1
    return new_image


but before using this function, I had to do this:

from PIL import Image
m = Image.open("test_image.jpg") # message
m = m.convert("1") # converts to boolean?