0

I'm trying to solve this CTF challenge Image Magic:

https://ctflearn.com/challenge/89

My code:

from PIL import Image
import numpy as np

out=np.asarray(Image.open("out copy.jpg"))

original_pixels=np.zeros([92,304], dtype=tuple)

newcol=-1
for out_col in range(0,27968):
    newrow=out_col%92
    if out_col%92==0:
        newcol+=1
    original_pixels[newrow,newcol]=out[0,out_col]


original=Image.fromarray(original_pixels,"RGB")
original.save("original.png")

The logic and everything should be correct, as it matches with a solution I found on the Internet, but for some reason, my code is producing gibberish:

original.png

The solution I found ( https://medium.com/nerd-for-tech/write-up-ctflearn-image-magic-2caf5d651913 ):

from PIL import Image

img = Image.open('out copy.jpg')
new_img = Image.new('RGB', (400, 400))

n_x = n_y = 0

for i in range(0, img.size[0]):
    r, g, b = img.getpixel((i, 0))
    n_x = (i % 92)

    if i % 92 == 0:
        n_y = n_y + 1

    new_img.putpixel((n_x, n_y), (r, g, b))

new_img.save('answer.jpg')

Which produces the correct image:

answer.jpg

As you can see, the logic is basically the same, the only difference is that I used np arrays and the Image.fromarray method to shift the pixels and create the original image. The solution just created a blank image and used the putpixel method to fill the pixels in.

I think the problem is with the fromarray function, but I can't figure out why/how, and existing questions/answers are not helping. This seems like a simple solve, but I'm not really familiar with these stuff. Any suggestions?

One Curious Person
  • 193
  • 1
  • 1
  • 4

2 Answers2

1

The main reason this does not work, is that you are creating your original_pixels array as an array of Python objects. I’m frankly not sure what exactly this does in the end, but it is needlessly complicated. If you create your array as a (width, height, 3) array of bytes instead, it works:

original_pixels=np.zeros([92, 304, 3], dtype=np.uint8)

Now, as an "exercise for the reader": Have a look at the reshape method of numpy’s ndarray objects. Could that be put to good use here?

Ture Pålsson
  • 6,088
  • 2
  • 12
  • 15
  • That is so interesting! This feels like a rabbit hole honestly. Could it also be something about the dtype? Even with your code, if the dtype is tuple or object, the code won't work. Originally, I had dtype=uint8 but without the 3 in the array, and it gave the error: ValueError: setting an array element with a sequence. – One Curious Person Dec 19 '22 at 01:28
  • assigning a tuple of the right length into a numpy array should work, e.g. `original_pixels[newrow,newcol,:] = (1,2,3)`, or even without the final slice (`:`) would work – Sam Mason Dec 19 '22 at 13:27
1

This solution worked for me: Image.fromarray just produces black image

PIL assumes a particular format. You need to multiply the values by 255 and convert to uint8.

data = (data*255).astype('uint8')