Trying to make an encode process but have an error line:
Look at my whole fuction ,please, for the whole getting it. I think it isn't big enough.
Trying to add the header to the file data:
#Add the header to the file data
headerdata = struct.pack("4s"+\
"I"+\
str(Header.MAX_FORMAT_LENGTH)+"s",header.magicnum, header.size, header.fformat)
filebytes = headerdata + data
Have an error:
str(Header.MAX_FORMAT_LENGTH)+"s",header.magicnum, header.size, header.fformat) struct.error: argument for 's' must be a bytes object
I was trying to change it:(this line, addin 'b')
str(Header.MAX_FORMAT_LENGTH)+b"s",header.magicnum, header.size, header.fformat)
Have another error:
str(Header.MAX_FORMAT_LENGTH)+b's',header.magicnum, header.size, header.fformat) TypeError: must be str, not bytes
the whole fucnton:
def encode(image, data, filename, encryption=False, password=""):
im = Image.open(image)
px = im.load()
#Create a header
header = Header()
header.size = len(data)
header.fformat = "" if (len(filename.split(os.extsep))<2)\
else filename.split(os.extsep)[1]
#Add the header to the file data
headerdata = struct.pack("4s"+\
"I"+\
str(Header.MAX_FORMAT_LENGTH)+"s",header.magicnum, header.size, header.fformat)
filebytes = headerdata + data
#Optional encryption step
if encrypt:
if password:
filebytes = encrypt(filebytes, password,\
padding=im.width*im.height - len(filebytes))
else:
print ("Password is empty, encryption skipped")
#Ensure the image is large enough to hide the data
if len(filebytes) > im.width*im.height:
print ("Image too small to encode the file. \
You can store 1 byte per pixel.")
exit()
for i in range(len(filebytes)):
coords = (i%im.width, i/im.width)
byte = ord(filebytes[i])
px[coords[0], coords[1]] = encode_in_pixel(byte, px[coords[0],\
coords[1]])
im.save("output.png", "PNG")
2 Answers 2
Your original code was correct, except that the type of header.magicnum was unexpected. Your code snippet should read
#Add the header to the file data
headerdata = struct.pack("4s"+\
"I"+\
str(Header.MAX_FORMAT_LENGTH)+"s","{:04d}".format(header.magicnum).encode('UTF-8'), header.size, header.fformat)
filebytes = headerdata + data
or some other suitable format code and encoding that turns header.magicnum into your expected result.
9 Comments
ValueError: Unknown format code 'd' for object of type 'str'header.magicnum.encode('UTF-8'); this will convert the string into a bytes object (and get rid of the "{:04d}".format() part).str(Header.MAX_FORMAT_LENGTH)+"s",header.magicnum.encode('UTF-8'), header.size, header.fformat) struct.error: argument for 's' must be a bytes object walking around one place.. if it's str, trying to encode , why does it want bytes object?Code
since you said they are all strings, here you go
headerdata = struct.pack("4s"+\
"I"+\
str(Header.MAX_FORMAT_LENGTH)+"s",header.magicnum.encode(), int(header.size), header.fformat.encode())
This should work for the formats and types you want
Explanation
According to this, and specifically section 7.1.2.2, we can find the types needed as arguments for the following format characters:
-----------------------------------------
|Formatting Character | Type (in python)|
-----------------------------------------
|s | integer |
-----------------------------------------
|I | bytes |
-----------------------------------------
and since the data you want to format is of type str, we need to change it.
Lets start with making a str to and integer since it's the simplest.
>>> x = '123'
>>> type(x)
str
>>> y = int(x)
>>> type(y)
int
Easy, all we need to do is call int() on our string.
Next up is turning a string into bytes. We use strings encode() method to do this (documentation)
>>> x = '123'
>>> type(x)
str
>>> y = e.encode()
>>> type(y)
bytes
>>> print(y)
b'123'
str...