How do I get the least significant bits of many bytes? - python

I'm trying to get lsb from the line of an image,I managed to get here:
from PIL import Image
import sys
challengeImg = Image.open('image.png')
pixels = challengeImg.load()
for x in range(2944):
red = (pixels[x,310][0])
bred = format(red,"b")
#print(green)
#print(bred)
green = (pixels[x,310][1])
bgreen = format(green,"b")
#print(bgreen)
#print(green)
Well, until then I'm fine but now my problem, I managed to create the following code:
num = 10100001
n = 0
lsb = num >> n &1
print(lsb)
It works, but only with one byte, I suppose that with for I can achieve something but I am very beginner and I have not managed to make it work, how I can do to extract the lsb from each byte in the line of pixels of the red channel (or green, I guess it's the same procedure)?
It occurs to me that I could use a dictionary to group the bits in bytes (1: 10011001, 2: 01100110 ...) and then use the loop to apply the lsb code in each byte, anyway I do not know how I can do this and i dont think it's the best way (maybe it's not even valid).
I have a .png image of 2944x1912 that contains information hidden in the least significant bits, the first code that I put is the script that I am developing, and so far what it does is get the information of the pixels of the red channel in the line 310 and transform them into binary.
The second code is the code to get the lsb of a byte which I need to implement in the first code, so the second code should somehow group all the bits in 8 and select the last one for I save in a variable, resulting in (2944/8 = 368 = 368 bytes.)

The solution that came to me might not be the most optimal. I'll look for a better solution if it does not suffice, but in the meanwhile:
num = 10100001
num_string = str(num)
lsb_string = num_string[len(num_string)-1]
lsb = int(lsb_string)
print(lsb)
# output: 1

It works, thats the code;
from PIL import Image
import sys
challengeImg = Image.open('challenge.png')
pixels = challengeImg.load()
for x in range(2944):
red = (pixels[x,310][0])
bred = format(red,"b")
#print(green)
#print(bred)
green = (pixels[x,310][1])
bgreen = format(green,"b")
#print(bgreen)
#print(green)
rnum = format(red,"b")
rnum_string = str(rnum)
rlsb_string = rnum_string[len(rnum_string)-1]
rlsb = int(rlsb_string)
print(rlsb, end="")
Thanks!

Related

Reading input lines for int objects separated with whitespace?

I'm trying to solve a programming problem that involves returning a boolean for an uploaded profile pic, matching its resolution with the one that I provide as input and returning a statement that I've described below. This is one such test case that is giving me errors:
180
3
640 480 CROP IT
320 200 UPLOAD ANOTHER
180 180 ACCEPTED
The first line reads the dimension that needs to be matched, the second line represents the number of test cases and the rest comprise of resolutions with whitespace separators. For each of the resolutions, the output shown for each line needs to be printed.
I've tried this, since it was the most natural thing I could think of and being very new to Python I/O:
from sys import stdin, stdout
dim = int(input())
n = int(input())
out = ''
for cases in range(0, n):
in1 = int(stdin.readline().rstrip('\s'))
in2 = int(stdin.readline().rstrip('\s'))
out += str(prof_pic(in1, in2, dim))+'\n'
stdout.write(out)
ValueError: invalid literal for int() with base 10 : '640 480\n'
prof_pic is the function that I'm abstaining from describing here to prevent the post getting too long. But I've written in such a way that the width and height params both get compared with dim and return an output. The problem is with reading those lines. What is the best way to read such lines with differing separators?
You can try this it is in python 3.x
dimention=int(input())
t=int(input())
for i in range(t):
a=list(map(int,input().split()))
Instead of:
in2 = int(stdin.readline().rstrip('\s'))
you may try:
in2 = map( int, stdin.readline().split()[:2])
and you get
in2 = [640, 480]
You're calling readline. As the name implies, this reads in a whole line. (If you're not sure what you're getting, you should try printing it out.) So, you get something like this:
640 480 CROP IT
You can't call int on that.
What you want to do is split that line into separate pieces like this:
['640', '480', 'CROP IT']
For example:
line = stdin.readline().rstrip('\s')
in1, in2, rest = line.split(None, 2)
Now you can convert those first two into ints:
in1 = int(in1)
in2 = int(in2)

Python Pillow Image.frombytes mode '1' bad result

Where am I wrong ? I want to create a basic white pict from bytes
from PIL import Image
if __name__ == "__main__":
data = [chr(1)] * 8192
data = "".join(data)
im = Image.frombytes('1', (128,64), data, 'raw')
im = im.convert("RGB")
im.save("image.png", "PNG")
But I get this:
Just use Image.new instead:
im = Image.new(mode='RGB', size=(128,64), color=(255,255,255))
If you really want to make it from bytes, it would be like this:
Image.frombytes(mode='RGB', size=(128,64), data=b'\xff'*128*64*3)
edit: Image.frombytes expects bytes, not a list of integers. To convert a list of integers to the right type, use this:
>>> bytes([0,1,2]) # Python 3
b'\x00\x01\x02'
>>> bytes(bytearray([0,1,2])) # Python 2
'\x00\x01\x02'
edit 2: mode='1' or the docs have bug (see comment thread). Assuming you have a list of zeros and ones, 1024 elements long, and you want to convert this to an 128x64 monochromatic image (one bit per pixel) then you'll have to pack the bytes manually:
bits = [int(not (y%13 and x%7)) for x in range(64) for y in range(128)]
# asymmetric grid
octets = [bits[i:i+8] for i in range(0, len(bits), 8)]
def bits2byte(bits8):
result = 0
for bit in bits8:
result <<= 1
result |= bit
return result
data = bytes(bytearray([bits2byte(octet) for octet in octets]))
im = Image.frombytes(mode='1', size=(128,64), data=data)
im.show()
Result:
In mode 1 each byte represents 8 pixels (there might be zero padding at end of each row if the width does not divide by 8). So to get a white image, you have to pass in only the byte b'\xff'
data = b'\xff' * 1024
im = Image.frombytes('1', (128,64), data)
Even if the Pillow docs say that there's one pixel per byte in this mode, that is not true for the frombytes and tobytes methods, at least.
Any other repeating input other than \xff (all white) or \x00 (all black) will give some sort of pinstripe pattern, like the one in your question.

reorder byte order in hex string (python)

I want to build a small formatter in python giving me back the numeric
values embedded in lines of hex strings.
It is a central part of my formatter and should be reasonable fast to
format more than 100 lines/sec (each line about ~100 chars).
The code below should give an example where I'm currently blocked.
'data_string_in_orig' shows the given input format. It has to be
byte swapped for each word. The swap from 'data_string_in_orig' to
'data_string_in_swapped' is needed. In the end I need the structure
access as shown. The expected result is within the comment.
Thanks in advance
Wolfgang R
#!/usr/bin/python
import binascii
import struct
## 'uint32 double'
data_string_in_orig = 'b62e000052e366667a66408d'
data_string_in_swapped = '2eb60000e3526666667a8d40'
print data_string_in_orig
packed_data = binascii.unhexlify(data_string_in_swapped)
s = struct.Struct('<Id')
unpacked_data = s.unpack_from(packed_data, 0)
print 'Unpacked Values:', unpacked_data
## Unpacked Values: (46638, 943.29999999943209)
exit(0)
array.arrays have a byteswap method:
import binascii
import struct
import array
x = binascii.unhexlify('b62e000052e366667a66408d')
y = array.array('h', x)
y.byteswap()
s = struct.Struct('<Id')
print(s.unpack_from(y))
# (46638, 943.2999999994321)
The h in array.array('h', x) was chosen because it tells array.array to regard the data in x as an array of 2-byte shorts. The important thing is that each item be regarded as being 2-bytes long. H, which signifies 2-byte unsigned short, works just as well.
This should do exactly what unutbu's version does, but might be slightly easier to follow for some...
from binascii import unhexlify
from struct import pack, unpack
orig = unhexlify('b62e000052e366667a66408d')
swapped = pack('<6h', *unpack('>6h', orig))
print unpack('<Id', swapped)
# (46638, 943.2999999994321)
Basically, unpack 6 shorts big-endian, repack as 6 shorts little-endian.
Again, same thing that unutbu's code does, and you should use his.
edit Just realized I get to use my favorite Python idiom for this... Don't do this either:
orig = 'b62e000052e366667a66408d'
swap =''.join(sum([(c,d,a,b) for a,b,c,d in zip(*[iter(orig)]*4)], ()))
# '2eb60000e3526666667a8d40'
The swap from 'data_string_in_orig' to 'data_string_in_swapped' may also be done with comprehensions without using any imports:
>>> d = 'b62e000052e366667a66408d'
>>> "".join([m[2:4]+m[0:2] for m in [d[i:i+4] for i in range(0,len(d),4)]])
'2eb60000e3526666667a8d40'
The comprehension works for swapping byte order in hex strings representing 16-bit words. Modifying it for a different word-length is trivial. We can make a general hex digit order swap function also:
def swap_order(d, wsz=4, gsz=2 ):
return "".join(["".join([m[i:i+gsz] for i in range(wsz-gsz,-gsz,-gsz)]) for m in [d[i:i+wsz] for i in range(0,len(d),wsz)]])
The input params are:
d : the input hex string
wsz: the word-size in nibbles (e.g for 16-bit words wsz=4, for 32-bit words wsz=8)
gsz: the number of nibbles which stay together (e.g for reordering bytes gsz=2, for reordering 16-bit words gsz = 4)
import binascii, tkinter, array
from tkinter import *
infile_read = filedialog.askopenfilename()
with open(infile, 'rb') as infile_:
infile_read = infile_.read()
x = (infile_read)
y = array.array('l', x)
y.byteswap()
swapped = (binascii.hexlify(y))
This is a 32 bit unsigned short swap i achieved with code very much the same as "unutbu's" answer just a little bit easier to understand. And technically binascii is not needed for the swap. Only array.byteswap is needed.

Billing aliens via POS printer and image print

I am trying to create a prototype to print bitmap data for a text file to my LAN enabled epson pos printer TM-T88V.
While I have no problems to send text and text formatting instructions, I dont understand, what I have to do, to make my printer print the data of the Arecibo message.
first few lines:
00000010101010000000000
00101000001010000000100
10001000100010010110010
10101010101010100100100
00000000000000000000000
00000000000011000000000
00000000001101000000000
00000000001101000000000
00000000010101000000000
00000000011111000000000
00000000000000000000000
11000011100011000011000
10000000000000110010000
11010001100011000011010
11111011111011111011111
00000000000000000000000
00010000000000000000010
00000000000000000000000
00001000000000000000001
The message has 73 rows and 23 columns resulting in 1679 picture elements. Each of this elements is defined by either a 1 for black or a 0 as white and should be printed as a square of 8x8 (or 16x16) dots. the result would result in
(source: satsig.net)
From the printer's specifications:
While — as I said — the connecting and sending to the printer is no problem, I just dont get, what this instruction want to tell me. What would in the case of the Arecibo message be
What numbers do I have to send to the printer? Do I need to send every dot? What does nL, nH specify the number of dots of the image data in the horizontal direction as (nL + nH × 256). mean?
Here is my simple Python program I use for prototyping:
# -*- coding: utf-8 -*-
import struct
import socket
def sendInstructions(mySocket,l):
for x in l:
mySocket.send(struct.pack('h', *[x]),1)
def emphasizeOn(mySocket):
sendInstructions(mySocket,[27,33,48])
def emphasizeOff(mySocket):
sendInstructions(mySocket,[27,33,0])
def lineFeed(mySocket,number):
for i in range(number):
sendInstructions(mySocket,[0x0a,])
def paperCut(mySocket):
sendInstructions(mySocket,[29,86,0])
def sendText(mySocket,string):
mySocket.send(string.encode('UTF-8'))
def main():
mySocket = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
mySocket.connect(('192.168.1.15',9100))
lines = ["Hello,","World!"]
emphasizeOff(mySocket)
lineFeed(mySocket,2)
for l in lines:
if lines.index(l) == 0:
emphasizeOn(mySocket)
else:
emphasizeOff(mySocket)
sendText(mySocket,l)
lineFeed(mySocket,2)
lineFeed(mySocket,4)
paperCut(mySocket)
mySocket.close()
if __name__=="__main__":
main()
This command generates one horizontal strip of the image at a time. The strip is either 8 or 24 dots tall, depending on the value of m.
nL and nH are the low and high bytes of an integer that specifies the width in dots of the horizontal strip of image. That width is computed as nL + nH * 256, so if you wanted the image to be 550 dots wide, then nH=2 and nL=38.
The argument d is the bitmap data; if the image strip is 8 dots tall, then each byte represents one column in the strip. If the strip is 24 dots tall, then three bytes represent one column.
So let's say you have arecibo in a WxH numpy array of ints, 1 or 0. You would:
data = np.zeros((W, H), dtype=np.ubyte)
## (fill in data here)
## Use m=33 since this is apparently the only mode with
## square pixels and also the highest resolution
## (unless it prints too slowly for your liking)
m = 33
nH = W // 256 ## note this is integer division, but SO's
## syntax hilighting thinks it looks like a comment.
nL = W % 256
## Divide the array into sections with shape Wx24:
for n in range(data.shape[1] // 24):
## Note that if the image height is not a multiple of 24,
## you'll have to pad it with zeros somehow.
strip = data[:, n*24:(n+1)*24]
## Convert each strip into a string of bytes:
strip = strip.reshape(W, 3, 8)
bytes = (strip * (2**np.arange(8)[np.newaxis, np.newaxis, :])).sum(axis=2) # magic
byteString = bytes.astype(np.ubyte).tostring()
## Send the command to POS

Reading bmp files in Python

Is there a way to read in a bmp file in Python that does not involve using PIL? PIL doesn't work with version 3, which is the one I have. I tried to use the Image object from graphics.py, Image(anchorPoint, filename), but that only seems to work with gif files.
In Python it can simply be read as:
import os
from scipy import misc
path = 'your_file_path'
image= misc.imread(os.path.join(path,'image.bmp'), flatten= 0)
## flatten=0 if image is required as it is
## flatten=1 to flatten the color layers into a single gray-scale layer
I realize that this is an old question, but I found it when solving this problem myself and I figured that this might help someone else in the future.
It's pretty easy actually to read a BMP file as binary data. Depending on how broad support and how many corner-cases you need to support of course.
Below is a simple parser that ONLY works for 1920x1080 24-bit BMP's (like ones saved from MS Paint). It should be easy to extend though. It spits out the pixel values as a python list like (255, 0, 0, 255, 0, 0, ...) for a red image as an example.
If you need more robust support there's information on how to properly read the header in answers to this question: How to read bmp file header in python?. Using that information you should be able to extend the simple parser below with any features you need.
There's also more information on the BMP file format over at wikipedia https://en.wikipedia.org/wiki/BMP_file_format if you need it.
def read_rows(path):
image_file = open(path, "rb")
# Blindly skip the BMP header.
image_file.seek(54)
# We need to read pixels in as rows to later swap the order
# since BMP stores pixels starting at the bottom left.
rows = []
row = []
pixel_index = 0
while True:
if pixel_index == 1920:
pixel_index = 0
rows.insert(0, row)
if len(row) != 1920 * 3:
raise Exception("Row length is not 1920*3 but " + str(len(row)) + " / 3.0 = " + str(len(row) / 3.0))
row = []
pixel_index += 1
r_string = image_file.read(1)
g_string = image_file.read(1)
b_string = image_file.read(1)
if len(r_string) == 0:
# This is expected to happen when we've read everything.
if len(rows) != 1080:
print "Warning!!! Read to the end of the file at the correct sub-pixel (red) but we've not read 1080 rows!"
break
if len(g_string) == 0:
print "Warning!!! Got 0 length string for green. Breaking."
break
if len(b_string) == 0:
print "Warning!!! Got 0 length string for blue. Breaking."
break
r = ord(r_string)
g = ord(g_string)
b = ord(b_string)
row.append(b)
row.append(g)
row.append(r)
image_file.close()
return rows
def repack_sub_pixels(rows):
print "Repacking pixels..."
sub_pixels = []
for row in rows:
for sub_pixel in row:
sub_pixels.append(sub_pixel)
diff = len(sub_pixels) - 1920 * 1080 * 3
print "Packed", len(sub_pixels), "sub-pixels."
if diff != 0:
print "Error! Number of sub-pixels packed does not match 1920*1080: (" + str(len(sub_pixels)) + " - 1920 * 1080 * 3 = " + str(diff) +")."
return sub_pixels
rows = read_rows("my image.bmp")
# This list is raw sub-pixel values. A red image is for example (255, 0, 0, 255, 0, 0, ...).
sub_pixels = repack_sub_pixels(rows)
Use pillow for this. After you installed it simply import it
from PIL import Image
Then you can load the BMP file
img = Image.open('path_to_file\file.bmp')
If you need the image to be a numpy array, use np.array
img = np.array(Image.open('path_to_file\file.bmp'))
The numpy array will only be 1D. Use reshape() to bring it into the right shape in case your image is RGB. For example:
np.array(Image.open('path_to_file\file.bmp')).reshape(512,512,3)
I had to work on a project where I needed to read a BMP file using python, it was quite interesting, actually the best way is to have a review on the BMP file format (https://en.wikipedia.org/wiki/BMP_file_format) then reading it as binairy file, to extract the data.
You will need to use the struct python library to perform the extraction
You can use this tutorial to see how it proceeds https://youtu.be/0Kwqdkhgbfw
Use the excellent matplotlib library
import matplotlib.pyplot as plt
im = plt.imread('image.bmp')
It depends what you are trying to achieve and on which platform?
Anyway using a C library to load BMP may work e.g. http://code.google.com/p/libbmp/ or http://freeimage.sourceforge.net/, and C libraries can be easily called from python e.g. using ctypes or wrapping it as a python module.
or you can compile this version of PIL https://github.com/sloonz/pil-py3k
If you're doing this in Windows, this site, should allow you to get PIL (and many other popular packages) up and running with most versions of Python: Unofficial Windows Binaries for Python Extension Packages
The common port of PIL to Python 3.x is called "Pillow".
Also I would suggest pygame library for simple tasks. It is a library, full of features for creating games - and reading from some common image formats is among them. Works with Python 3.x as well.

Categories