Reputation: 87
I am getting the error too many values to unpack (expected 3)
.
When i add []
in case it is a tuple itself it i get the error not enough values to unpack (expected 3, got 1)
The error rises on line 50, r, g, b = hex2rgb(newpix)
I am going to share the entire code as i am not sure if this is the only error i am getting.
My goal is to insert a string into a .png file. I used to use python around 10 years back, i am a C# user so excuse me if this is too nooby as a question
Thank you P.S. i am not very good at expressing myself, feel free to edit the post
from PIL import Image
import binascii
import optparse
def rgb2hex(r, g, b):
return '#{:02x}{:02x}{:02x}'.format(r, g, b)
def hex2rgb(hexcode):
return tuple(map(ord, hexcode[1:]))
def str2bin(message):
binary = bin(int(binascii.hexlify(message.encode()), 16))
return binary[2:]
def bin2str(binary):
message = binascii.unhexlify('%x' % (int('0b' + binary, 2)))
return message
def encode(hexcode, digit):
if hexcode[-1] in ('0', '1', '2', '3', '4', '5'):
hexcode = hexcode[:-1] + digit
return hexcode
else:
return None
def decode(hexcode):
if hexcode[-1] in ('0', '1'):
return hexcode[-1]
else:
return None
def hide(filename, message):
img = Image.open(filename)
binary = str2bin(message) + '1111111111111110'
if img.mode in ('RGBA'):
img = img.convert('RGBA')
datas = img.getdata()
newData = []
digit = 0
temp = ''
for item in datas:
if (digit < len(binary)):
newpix = encode(rgb2hex(item[0], item[1], item[2]), binary[digit])
if newpix == None:
newData.append(item)
else:
r, g, b = [hex2rgb(newpix)]
newData.append((r, g, b, 255))
digit =+ 1
else:
newData.append(item)
img.putdata(newData)
img.save(filename, "PNG")
return "Completed!"
return "Incorrect Image mode, couldn't hide"
def retr(filename):
img = Image.open(filename)
binary = ''
if img.mode in ('RGBA'):
img = img.convert('RGBA')
datas = img.getdata()
for item in datas:
digit = decode(rgb2hex(item[0], item[1], item[2]))
if digit == None:
pass
else:
binary = binary + digit
if (binary[-16:] == '1111111111111110'):
print("Success")
return bin2str(binary[:-16])
return bin2str(binary)
return "Incorrect Image mode, couldn't retrieve"
def Main():
parser = optparse.OptionParser('usage %prog ' + '-e/-d <target file>')
parser.add_option('-e', dest = 'hide', type = 'string', help = 'target picture path to hide text')
parser.add_option('-d', dest = 'retr', type = 'string', help = 'target picture to retrieve text')
(options, args) = parser.parse_args()
if (options.hide != None):
text = input("Enter a message to hide: ")
print(hide(options.hide, text))
elif(options.retr != None):
print(retr(optrions.retr))
else:
print(parser.usage)
exit(0)
if __name__ == '__main__':
Main()
Upvotes: 0
Views: 368
Reputation: 330
>>> hex2rgb('#abcdef')
(97, 98, 99, 100, 101, 102)
Here I use your hex2rgb()
function without assigning the output to any variables. It returns 6 values, as you would expect since you decode every char from the hexadecimal value (a
for instance) into an integer unicode code point that corresponds to hexadecimal a
: 97
. (see documentation or ord() here)
>>> r,g,b = hex2rgb('#abcdef')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 3)
When trying to unpack them into three variables, it raises an error because your function returns 6 variables instead of the expected 3.
>>> r,g,b = [hex2rgb('#abcdef')]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 3, got 1)
Your approach to wrap the 6 integers into a list reduces the return value from being 6 variables into being only 1 value (the list with 6 items), and thus this does not solve your problem.
To solve your problem you should find a way to end up with 3 integers instead of 6. For this, you need a different approach for decoding your HEX value.
The RGB pairs in my example are made up of Red=AB, Green=CD, Blue=EF. By using map()
with ord()
you translate A
and B
separately to an integer, which is not what you want, as you end up with 2 integers (97
and 98
) instead of 1 integer (171
) corresponding to the AB
value.
So what you want is:
>>> int("0xAB",0)
171
As you can see, converting AB
together would return the right value (171). See this answer for an example of how to do that. Modify your hex2rgb()
to do this.
Last but not least, your approach to use ord()
to decode the chars into integers is interesting, but might not be correct, as A
and a
have a different unicode code point value (A = 65
, a = 97
), and thus they result in different values for your color. In HEX-color codes there is no difference between uppercase or lowercase letters. When you use the method with int()
as described above, the result will be the same for characters in lower- or uppercase, and thus be more correct.
Upvotes: 1