I have some code which is fine for creating greyscale (8bpp) images but I need to create 1bpp (binary) also for a printer. I have seen 2 posts here but cannot understand how they fix the issue. Can't format BMP image data to 1 bit per pixel in PIL I have pillow installed but call it using PIL as all the tutorials I have read seem to say to import Image from PIL.
I have a method called conv_to_1bpp which sets anything at 255 equal to 1, this is still making 8bpp images though.
Code
from PIL import Image
import numpy as np
import os
import sys
import struct
class BmpMaker:
def __init__(self):
self.ffp = None
self.img_width = None
self.img_height = None
self.ws_activation = None
self.bpp = None
def make_image(self, img_width, img_height, ws_activation):
"""Creates a bitmap."""
self.ffp = None
self.img_width = img_width
self.img_height = img_height
self.ws_activation = ws_activation
# Create new black image - L mode for b/w
img = Image.new('L', (img_width, img_height))
# Convert to Numpy array for easy processing
na = np.array(img)
# set the amount of white space activation
white_rows = ws_activation
# make white lines
na[0:white_rows, 0:999] = 255
# Revert to PIL Image from Numpy array and save
self.ffp = self.make_img_title(img_width, img_height, ws_activation)
Image.fromarray(na).save(self.ffp)
self.bpp = self.get_bitdepth()
return self.ffp
def make_img_title(self, img_width, img_height, ws_activation):
if ws_activation == 0:
mystr = f"{img_height}x{img_width}"
elif ws_activation is not None:
mystr = f"{ws_activation}_{img_height}x{img_width}"
self.ffp = os.path.join(os.getcwd(), mystr + ".bmp")
print("img_ffp : ", self.ffp)
return self.ffp
def get_bitdepth(self):
# Read first 100 bytes
with open(self.ffp, 'rb') as f:
BMP = f.read(100)
if BMP[0:2] != b'BM':
sys.exit('ERROR: Incorrect BMP signature')
# Get BITMAPINFOHEADER size - https://en.wikipedia.org/wiki/BMP_file_format
BITMAPINFOHEADERSIZE = struct.unpack('<i', BMP[14:18])[0]
okSizes = [40, 52, 56, 108, 124]
if BITMAPINFOHEADERSIZE not in okSizes:
sys.exit(f'ERROR: BITMAPINFOHEADER size was {BITMAPINFOHEADERSIZE},'
f' expected one of {okSizes}')
# Get bits per pixel
self.bpp = struct.unpack('<H', BMP[28:30])[0]
print(f'bbp: {self.bpp}')
return self.bpp
def get_img_bitdepth(self, img):
# Read first 100 bytes
with open(img, 'rb') as f:
BMP = f.read(100)
if BMP[0:2] != b'BM':
sys.exit('ERROR: Incorrect BMP signature')
# Get BITMAPINFOHEADER size - https://en.wikipedia.org/wiki/BMP_file_format
BITMAPINFOHEADERSIZE = struct.unpack('<i', BMP[14:18])[0]
okSizes = [40, 52, 56, 108, 124]
if BITMAPINFOHEADERSIZE not in okSizes:
sys.exit(f'ERROR: BITMAPINFOHEADER size was {BITMAPINFOHEADERSIZE},'
f' expected one of {okSizes}')
# Get bits per pixel
img_bpp = struct.unpack('<H', BMP[28:30])[0]
print(f'bbp: {img_bpp}')
return img_bpp
def conv_to_1bpp(self):
img = Image.open(self.ffp)
arr = np.array(img)
#print(arr)
# Set all values at indices where the array equals 255 to 1.
arr[arr==255] = 1
print('\n'*3, arr)
Image.fromarray(arr).save("my_img.bmp")
print(self.get_img_bitdepth("my_img.bmp"))
if __name__ == "__main__":
import PIL
print('Pillow Version:', PIL.__version__)
bm = BmpMaker()
base_image = bm.make_image(1000, 8, 5)
print("bitmap ffp: ", bm.ffp)
print("bitmap bitdepth : ", bm.bpp)
bm.conv_to_1bpp()
when creating the initial image use mode '1' instead of 'L'
# Create new black image - L mode for b/w, '1' for binary
img = Image.new('1', (img_width, img_height))