2

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")
3
  • Your error has to do with the other arguments, not the format string. It's saying that where in the format string there is an "s", it is expecting a bytes object. check this out, look at section 7.1.2.2 Commented Jul 20, 2017 at 19:25
  • what are the types for header.magicnum, header.size, header.fformat Commented Jul 20, 2017 at 19:31
  • @jacoblaw it should be str... Commented Jul 20, 2017 at 19:39

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

9 Comments

Can't get. Is there some missing of ` " ` in your answer?
Yes there is, fixed.
have another error, urghhhhhhh ;(((( It writes: ValueError: Unknown format code 'd' for object of type 'str'
If header.magicnum is already a string, then just use header.magicnum.encode('UTF-8'); this will convert the string into a bytes object (and get rid of the "{:04d}".format() part).
Doing smth like this 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?
|
0

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'

1 Comment

@x20 added the explanation

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.