Related
I try to print an image from python script on Debian 10 using cups:
import cups
def printImageLinux(image_name):
conn = cups.Connection()
printer = conn.getDefault()
conn.printFile(printer, image_name, 'suo_ticket', {})
Finally, the image went to print but I see canceling of printing and error in Cups user interface (localhost:631) with a message:
"The page setup information was not valid."
CUPS message screenshot
I suppose that I should make some preparation of image sending to print, but I didn't find any information about it.
I can print the same image from Windows using win32print module and code:
import os, sys
from win32 import win32api, win32print
from PIL import Image, ImageWin
def printImage(image_name):
# Constants for GetDeviceCaps
# HORZRES / VERTRES = printable area
HORZRES = 8
VERTRES = 10
# LOGPIXELS = dots per inch
LOGPIXELSX = 88
LOGPIXELSY = 90
# PHYSICALWIDTH/HEIGHT = total area
PHYSICALWIDTH = 110
PHYSICALHEIGHT = 111
# PHYSICALOFFSETX/Y = left / top margin
PHYSICALOFFSETX = 112
PHYSICALOFFSETY = 113
printer_name = win32print.GetDefaultPrinter ()
file_name = image_name
#
# You can only write a Device-independent bitmap
# directly to a Windows device context; therefore
# we need (for ease) to use the Python Imaging
# Library to manipulate the image.
#
# Create a device context from a named printer
# and assess the printable size of the paper.
#
hDC = win32ui.CreateDC ()
hDC.CreatePrinterDC (printer_name)
printable_area = hDC.GetDeviceCaps (HORZRES), hDC.GetDeviceCaps (VERTRES)
printer_size = hDC.GetDeviceCaps (PHYSICALWIDTH), hDC.GetDeviceCaps (PHYSICALHEIGHT)
printer_margins = hDC.GetDeviceCaps (PHYSICALOFFSETX), hDC.GetDeviceCaps (PHYSICALOFFSETY)
#
# Open the image, rotate it if it's wider than
# it is high, and work out how much to multiply
# each pixel by to get it as big as possible on
# the page without distorting.
#
bmp = Image.open (file_name)
if bmp.size[0] > bmp.size[1]:
bmp = bmp.rotate (90)
ratios = [1.0 * printable_area[0] / bmp.size[0], 1.0 * printable_area[1] / bmp.size[1]]
scale = min (ratios)
#
# Start the print job, and draw the bitmap to
# the printer device at the scaled size.
#
hDC.StartDoc (file_name)
hDC.StartPage ()
dib = ImageWin.Dib (bmp)
scaled_width, scaled_height = [int (scale * i) for i in bmp.size]
x1 = int ((printer_size[0] - scaled_width) / 2)
y1 = int ((printer_size[1] - scaled_height) / 2)
x2 = x1 + scaled_width
y2 = y1 + scaled_height
dib.draw (hDC.GetHandleOutput (), (x1, y1, x2, y2))
hDC.EndPage ()
hDC.EndDoc ()
hDC.DeleteDC ()
It works correctly.
Can I make the same operations with the image in Debian?
Thank you for any help!
Problem was solved with using PIL module. Working code:
import cups
from PIL import Image
def printImageLinux(image_name):
conn = cups.Connection()
printer = conn.getDefault()
image1 = Image.open(image_name)
im1 = image1.convert('RGB')
im1.save('temp_image.pdf')
conn.printFile(printer, 'temp_image.pdf', 'suo_ticket', {'fit-to-page':'True'})
I'm getting a little desperate, I'm trying to display the current time via a Raspberry pi with an HD44780 and an I2C chip. This works quite well, but now I want that the backlight remains off. The corresponding code snippet that my script sends is interpreted correctly, but every time the time is updated (and the LCD is supposed to write a new text) the backlight flashes briefly. I need this functionality programmatically, since, as soon as the problem is solved, still further functionality is to be added to the Script, in which the backlight is to be switched on again temporarily.
Running Script:
#!/usr/bin/env python3.2.3
#Date And Time Script
from time import sleep, strftime
from subprocess import *
import lcddriver
lcd = lcddriver.lcd()
def run_cmd(cmd):
p = Popen(cmd, shell = True, stdout = PIPE)
output = p.communicate()[0]
return output
lcd.lcd_clear()
while True:
lcd.lcd_display_string(strftime('%d.%m.%Y %H:%M'), 1)
lcd.lcd_device.write_cmd( 0x03 | 1 )
sleep(1)
Imported Script
import i2c_lib
from time import *
# LCD Address
ADDRESS = 0x27 #Update Address For LCD Here
# commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80
# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00
# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00
# flags for backlight control
LCD_BACKLIGHT = 0x08
LCD_NOBACKLIGHT = 0x00
En = 0b00000100 # Enable bit
Rw = 0b00000010 # Read/Write bit
Rs = 0b00000001 # Register select bit
class lcd:
#initializes objects and lcd
def __init__(self):
self.lcd_device = i2c_lib.i2c_device(ADDRESS)
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x02)
self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
sleep(0.2)
# clocks EN to latch command
def lcd_strobe(self, data):
self.lcd_device.write_cmd(data | En | LCD_BACKLIGHT)
sleep(.0005)
self.lcd_device.write_cmd(((data & ~En) | LCD_BACKLIGHT))
sleep(.0001)
def lcd_write_four_bits(self, data):
self.lcd_device.write_cmd(data | LCD_BACKLIGHT)
self.lcd_strobe(data)
# write a command to lcd
def lcd_write(self, cmd, mode=0):
self.lcd_write_four_bits(mode | (cmd & 0xF0))
self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0))
# put string function
def lcd_display_string(self, string, line):
if line == 1:
self.lcd_write(0x80)
if line == 2:
self.lcd_write(0xC0)
if line == 3:
self.lcd_write(0x94)
if line == 4:
self.lcd_write(0xD4)
for char in string:
self.lcd_write(ord(char), Rs)
# clear lcd and set to home
def lcd_clear(self):
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_RETURNHOME)
I am writing code that reads a file and sends it to an 20x4 LCD and I have buttons so I can move up and down the file
`
import math
import time
import linecache
import Adafruit_CharLCD as LCD
lcd = LCD.Adafruit_CharLCDPlate()
lcd.set_backlight (1)
end = 0
page = 0
load = 0
lineno = 0
txtfilename = ('file.txt' % spot)
while (end != 2):
if lcd.is_pressed(LCD.UP) or lcd.is_pressed(LCD.DOWN):
lcd.clear()
lineno += 1 if lcd.is_pressed(LCD.UP) else -1
text1 = linecache.getline(txtfilename, lineno)
text2 = linecache.getline(txtfilename, lineno +1)
text3 = linecache.getline(txtfilename, lineno +2)
text4 = linecache.getline(txtfilename, lineno +3)
print lineno
lcd.message(("%s%s%s%s") % (text1, text2, text3, text4))
print "%s" % text1
time.sleep (0.5)
end = 0
elif lcd.is_pressed(LCD.SELECT):
lcd.clear()
lcd.message ("Press agine to quit")
end +=1
#load
time.sleep (0.5)
lcd.clear()
lcd.message ('Goodbye')
time.sleep (0.5)
lcd.clear()
lcd.set_backlight (0)
`
The file that I will be reading will have lots of lines in it but each line will be under the 20 character
When I run this the 1st 4 lines are displayed but then I get the following
File "spot.py", line 54, in <module>
lcd.message(("%s%s%s%s") % (text1, text2, text3, text4))
File "/home/pi/me/Adafruit_CharLCD.py", line 246, in message
self.set_cursor(col, line)
File "/home/pi/me/Adafruit_CharLCD.py", line 182, in set_cursor
self.write8(LCD_SETDDRAMADDR | (col + LCD_ROW_OFFSETS[row]))
IndexError: tuple index out of range
I have seen other posts like this problem but I can't get them to work. Can anyone help me please?
Here is the Adafruit code I am using
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import time
import Adafruit_GPIO as GPIO
import Adafruit_GPIO.I2C as I2C
import Adafruit_GPIO.MCP230xx as MCP
import Adafruit_GPIO.PWM as PWM
# Commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80
# Entry flags
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# Control flags
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00
# Move flags
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00
# Function set flags
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_4LINE = 0x54
LCD_3LINE = 0x14
LCD_2LINE = 0x40
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00
# Offset for up to 4 rows.
LCD_ROW_OFFSETS = (0x00, 0x40, 0x14, 0x54)
# Char LCD plate GPIO numbers.
LCD_PLATE_RS = 15
LCD_PLATE_RW = 14
LCD_PLATE_EN = 13
LCD_PLATE_D4 = 12
LCD_PLATE_D5 = 11
LCD_PLATE_D6 = 10
LCD_PLATE_D7 = 9
LCD_PLATE_RED = 6
LCD_PLATE_GREEN = 7
LCD_PLATE_BLUE = 8
# Char LCD plate button names.
SELECT = 0
RIGHT = 1
DOWN = 2
UP = 3
LEFT = 4
class Adafruit_CharLCD(object):
"""Class to represent and interact with an HD44780 character LCD display."""
def __init__(self, rs, en, d4, d5, d6, d7, cols, lines, backlight=None,
invert_polarity=True,
enable_pwm=False,
gpio=GPIO.get_platform_gpio(),
pwm=PWM.get_platform_pwm(),
initial_backlight=1.0):
"""Initialize the LCD. RS, EN, and D4...D7 parameters should be the pins
connected to the LCD RS, clock enable, and data line 4 through 7 connections.
The LCD will be used in its 4-bit mode so these 6 lines are the only ones
required to use the LCD. You must also pass in the number of columns and
lines on the LCD.
If you would like to control the backlight, pass in the pin connected to
the backlight with the backlight parameter. The invert_polarity boolean
controls if the backlight is one with a LOW signal or HIGH signal. The
default invert_polarity value is True, i.e. the backlight is on with a
LOW signal.
You can enable PWM of the backlight pin to have finer control on the
brightness. To enable PWM make sure your hardware supports PWM on the
provided backlight pin and set enable_pwm to True (the default is False).
The appropriate PWM library will be used depending on the platform, but
you can provide an explicit one with the pwm parameter.
The initial state of the backlight is ON, but you can set it to an
explicit initial state with the initial_backlight parameter (0 is off,
1 is on/full bright).
You can optionally pass in an explicit GPIO class,
for example if you want to use an MCP230xx GPIO extender. If you don't
pass in an GPIO instance, the default GPIO for the running platform will
be used.
"""
# Save column and line state.
self._cols = cols
self._lines = lines
# Save GPIO state and pin numbers.
self._gpio = gpio
self._rs = rs
self._en = en
self._d4 = d4
self._d5 = d5
self._d6 = d6
self._d7 = d7
# Save backlight state.
self._backlight = backlight
self._pwm_enabled = enable_pwm
self._pwm = pwm
self._blpol = not invert_polarity
# Setup all pins as outputs.
for pin in (rs, en, d4, d5, d6, d7):
gpio.setup(pin, GPIO.OUT)
# Setup backlight.
if backlight is not None:
if enable_pwm:
pwm.start(backlight, self._pwm_duty_cycle(initial_backlight))
else:
gpio.setup(backlight, GPIO.OUT)
gpio.output(backlight, self._blpol if initial_backlight else not self._blpol)
# Initialize the display.
self.write8(0x33)
self.write8(0x32)
# Initialize display control, function, and mode registers.
self.displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF
self.displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_2LINE | LCD_5x8DOTS
self.displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT
# Write registers.
self.write8(LCD_DISPLAYCONTROL | self.displaycontrol)
self.write8(LCD_FUNCTIONSET | self.displayfunction)
self.write8(LCD_ENTRYMODESET | self.displaymode) # set the entry mode
self.clear()
def home(self):
"""Move the cursor back to its home (first line and first column)."""
self.write8(LCD_RETURNHOME) # set cursor position to zero
self._delay_microseconds(3000) # this command takes a long time!
def clear(self):
"""Clear the LCD."""
self.write8(LCD_CLEARDISPLAY) # command to clear display
self._delay_microseconds(3000) # 3000 microsecond sleep, clearing the display takes a long time
def set_cursor(self, col, row):
"""Move the cursor to an explicit column and row position."""
# Clamp row to the last row of the display.
if row > self._lines:
row = self._lines - 1
# Set location.
self.write8(LCD_SETDDRAMADDR | (col + LCD_ROW_OFFSETS[row]))
def enable_display(self, enable):
"""Enable or disable the display. Set enable to True to enable."""
if enable:
self.displaycontrol |= LCD_DISPLAYON
else:
self.displaycontrol &= ~LCD_DISPLAYON
self.write8(LCD_DISPLAYCONTROL | self.displaycontrol)
def show_cursor(self, show):
"""Show or hide the cursor. Cursor is shown if show is True."""
if show:
self.displaycontrol |= LCD_CURSORON
else:
self.displaycontrol &= ~LCD_CURSORON
self.write8(LCD_DISPLAYCONTROL | self.displaycontrol)
def blink(self, blink):
"""Turn on or off cursor blinking. Set blink to True to enable blinking."""
if blink:
self.displaycontrol |= LCD_BLINKON
else:
self.displaycontrol &= ~LCD_BLINKON
self.write8(LCD_DISPLAYCONTROL | self.displaycontrol)
def move_left(self):
"""Move display left one position."""
self.write8(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT)
def move_right(self):
"""Move display right one position."""
self.write8(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT)
def set_left_to_right(self):
"""Set text direction left to right."""
self.displaymode |= LCD_ENTRYLEFT
self.write8(LCD_ENTRYMODESET | self.displaymode)
def set_right_to_left(self):
"""Set text direction right to left."""
self.displaymode &= ~LCD_ENTRYLEFT
self.write8(LCD_ENTRYMODESET | self.displaymode)
def autoscroll(self, autoscroll):
"""Autoscroll will 'right justify' text from the cursor if set True,
otherwise it will 'left justify' the text.
"""
if autoscroll:
self.displaymode |= LCD_ENTRYSHIFTINCREMENT
else:
self.displaymode &= ~LCD_ENTRYSHIFTINCREMENT
self.write8(LCD_ENTRYMODESET | self.displaymode)
def message(self, text):
"""Write text to display. Note that text can include newlines."""
line = 0
# Iterate through each character.
for char in text:
# Advance to next line if character is a new line.
if char == '\n':
line += 1
# Move to left or right side depending on text direction.
col = 0 if self.displaymode & LCD_ENTRYLEFT > 0 else self._cols-1
self.set_cursor(col, line)
# Write the character to the display.
else:
self.write8(ord(char), True)
def set_backlight(self, backlight):
"""Enable or disable the backlight. If PWM is not enabled (default), a
non-zero backlight value will turn on the backlight and a zero value will
turn it off. If PWM is enabled, backlight can be any value from 0.0 to
1.0, with 1.0 being full intensity backlight.
"""
if self._backlight is not None:
if self._pwm_enabled:
self._pwm.set_duty_cycle(self._backlight, self._pwm_duty_cycle(backlight))
else:
self._gpio.output(self._backlight, self._blpol if backlight else not self._blpol)
def write8(self, value, char_mode=False):
"""Write 8-bit value in character or data mode. Value should be an int
value from 0-255, and char_mode is True if character data or False if
non-character data (default).
"""
# One millisecond delay to prevent writing too quickly.
self._delay_microseconds(1000)
# Set character / data bit.
self._gpio.output(self._rs, char_mode)
# Write upper 4 bits.
self._gpio.output_pins({ self._d4: ((value >> 4) & 1) > 0,
self._d5: ((value >> 5) & 1) > 0,
self._d6: ((value >> 6) & 1) > 0,
self._d7: ((value >> 7) & 1) > 0 })
self._pulse_enable()
# Write lower 4 bits.
self._gpio.output_pins({ self._d4: (value & 1) > 0,
self._d5: ((value >> 1) & 1) > 0,
self._d6: ((value >> 2) & 1) > 0,
self._d7: ((value >> 3) & 1) > 0 })
self._pulse_enable()
def create_char(self, location, pattern):
"""Fill one of the first 8 CGRAM locations with custom characters.
The location parameter should be between 0 and 7 and pattern should
provide an array of 8 bytes containing the pattern. E.g. you can easyly
design your custom character at http://www.quinapalus.com/hd44780udg.html
To show your custom character use eg. lcd.message('\x01')
"""
# only position 0..7 are allowed
location &= 0x7
self.write8(LCD_SETCGRAMADDR | (location << 3))
for i in range(8):
self.write8(pattern[i], char_mode=True)
def _delay_microseconds(self, microseconds):
# Busy wait in loop because delays are generally very short (few microseconds).
end = time.time() + (microseconds/1000000.0)
while time.time() < end:
pass
def _pulse_enable(self):
# Pulse the clock enable line off, on, off to send command.
self._gpio.output(self._en, False)
self._delay_microseconds(1) # 1 microsecond pause - enable pulse must be > 450ns
self._gpio.output(self._en, True)
self._delay_microseconds(1) # 1 microsecond pause - enable pulse must be > 450ns
self._gpio.output(self._en, False)
self._delay_microseconds(1) # commands need > 37us to settle
def _pwm_duty_cycle(self, intensity):
# Convert intensity value of 0.0 to 1.0 to a duty cycle of 0.0 to 100.0
intensity = 100.0*intensity
# Invert polarity if required.
if not self._blpol:
intensity = 100.0-intensity
return intensity
class Adafruit_RGBCharLCD(Adafruit_CharLCD):
"""Class to represent and interact with an HD44780 character LCD display with
an RGB backlight."""
def __init__(self, rs, en, d4, d5, d6, d7, cols, lines, red, green, blue,
gpio=GPIO.get_platform_gpio(),
invert_polarity=True,
enable_pwm=False,
pwm=PWM.get_platform_pwm(),
initial_color=(1.0, 1.0, 1.0)):
"""Initialize the LCD with RGB backlight. RS, EN, and D4...D7 parameters
should be the pins connected to the LCD RS, clock enable, and data line
4 through 7 connections. The LCD will be used in its 4-bit mode so these
6 lines are the only ones required to use the LCD. You must also pass in
the number of columns and lines on the LCD.
The red, green, and blue parameters define the pins which are connected
to the appropriate backlight LEDs. The invert_polarity parameter is a
boolean that controls if the LEDs are on with a LOW or HIGH signal. By
default invert_polarity is True, i.e. the backlight LEDs are on with a
low signal. If you want to enable PWM on the backlight LEDs (for finer
control of colors) and the hardware supports PWM on the provided pins,
set enable_pwm to True. Finally you can set an explicit initial backlight
color with the initial_color parameter. The default initial color is
white (all LEDs lit).
You can optionally pass in an explicit GPIO class,
for example if you want to use an MCP230xx GPIO extender. If you don't
pass in an GPIO instance, the default GPIO for the running platform will
be used.
"""
super(Adafruit_RGBCharLCD, self).__init__(rs, en, d4, d5, d6, d7,
cols,
lines,
enable_pwm=enable_pwm,
backlight=None,
invert_polarity=invert_polarity,
gpio=gpio,
pwm=pwm)
self._red = red
self._green = green
self._blue = blue
# Setup backlight pins.
if enable_pwm:
# Determine initial backlight duty cycles.
rdc, gdc, bdc = self._rgb_to_duty_cycle(initial_color)
pwm.start(red, rdc)
pwm.start(green, gdc)
pwm.start(blue, bdc)
else:
gpio.setup(red, GPIO.OUT)
gpio.setup(green, GPIO.OUT)
gpio.setup(blue, GPIO.OUT)
self._gpio.output_pins(self._rgb_to_pins(initial_color))
def _rgb_to_duty_cycle(self, rgb):
# Convert tuple of RGB 0-1 values to tuple of duty cycles (0-100).
red, green, blue = rgb
# Clamp colors between 0.0 and 1.0
red = max(0.0, min(1.0, red))
green = max(0.0, min(1.0, green))
blue = max(0.0, min(1.0, blue))
return (self._pwm_duty_cycle(red),
self._pwm_duty_cycle(green),
self._pwm_duty_cycle(blue))
def _rgb_to_pins(self, rgb):
# Convert tuple of RGB 0-1 values to dict of pin values.
red, green, blue = rgb
return { self._red: self._blpol if red else not self._blpol,
self._green: self._blpol if green else not self._blpol,
self._blue: self._blpol if blue else not self._blpol }
def set_color(self, red, green, blue):
"""Set backlight color to provided red, green, and blue values. If PWM
is enabled then color components can be values from 0.0 to 1.0, otherwise
components should be zero for off and non-zero for on.
"""
if self._pwm_enabled:
# Set duty cycle of PWM pins.
rdc, gdc, bdc = self._rgb_to_duty_cycle((red, green, blue))
self._pwm.set_duty_cycle(self._red, rdc)
self._pwm.set_duty_cycle(self._green, gdc)
self._pwm.set_duty_cycle(self._blue, bdc)
else:
# Set appropriate backlight pins based on polarity and enabled colors.
self._gpio.output_pins({self._red: self._blpol if red else not self._blpol,
self._green: self._blpol if green else not self._blpol,
self._blue: self._blpol if blue else not self._blpol })
def set_backlight(self, backlight):
"""Enable or disable the backlight. If PWM is not enabled (default), a
non-zero backlight value will turn on the backlight and a zero value will
turn it off. If PWM is enabled, backlight can be any value from 0.0 to
1.0, with 1.0 being full intensity backlight. On an RGB display this
function will set the backlight to all white.
"""
self.set_color(backlight, backlight, backlight)
class Adafruit_CharLCDPlate(Adafruit_RGBCharLCD):
"""Class to represent and interact with an Adafruit Raspberry Pi character
LCD plate."""
def __init__(self, address=0x20, busnum=I2C.get_default_bus(), cols=20, lines=4):
"""Initialize the character LCD plate. Can optionally specify a separate
I2C address or bus number, but the defaults should suffice for most needs.
Can also optionally specify the number of columns and lines on the LCD
(default is 20x4).
"""
# Configure MCP23017 device.
self._mcp = MCP.MCP23017(address=address, busnum=busnum)
# Set LCD R/W pin to low for writing only.
self._mcp.setup(LCD_PLATE_RW, GPIO.OUT)
self._mcp.output(LCD_PLATE_RW, GPIO.LOW)
# Set buttons as inputs with pull-ups enabled.
for button in (SELECT, RIGHT, DOWN, UP, LEFT):
self._mcp.setup(button, GPIO.IN)
self._mcp.pullup(button, True)
# Initialize LCD (with no PWM support).
super(Adafruit_CharLCDPlate, self).__init__(LCD_PLATE_RS, LCD_PLATE_EN,
LCD_PLATE_D4, LCD_PLATE_D5, LCD_PLATE_D6, LCD_PLATE_D7, cols, lines,
LCD_PLATE_RED, LCD_PLATE_GREEN, LCD_PLATE_BLUE, enable_pwm=False,
gpio=self._mcp)
def is_pressed(self, button):
"""Return True if the provided button is pressed, False otherwise."""
if button not in set((SELECT, RIGHT, DOWN, UP, LEFT)):
raise ValueError('Unknown button, must be SELECT, RIGHT, DOWN, UP, or LEFT.')
return self._mcp.input(button) == GPIO.LOW
The text you pass to lcd.message has four newlines in it due to being composed of four lines read from the file. But the LCD only has four lines, so it supports only text with up to three newlines. The fourth newline tries to move the cursor past the last row and causes the error. Remove the last newline (e.g. with .rstrip('\n')) to fix this.
msg = "%s%s%s%s" % (text1, text2, text3, text4)
lcd.message(msg.rstrip('\n'))
Edit: The library you're using tries to prevent this from being a problem even if you pass in too many newlines, but there's a bug in their check. In set_cursor:
# Clamp row to the last row of the display.
if row > self._lines:
row = self._lines - 1
The > should be >=.
I've a color list file I read it into a python list and I'd like to create one (or several) image(s) composed by squares with background color read from file and as foreground html string of the color (written with white). I.e. I read #ff0000 from input file then I create a 100x100 square with red background and a white string "#ff0000" as foreground...and so on for each color in input file.
This is my script:
#!/usr/bin/env python
from gimpfu import *
def readColors(ifc):
"""Read colors from input file and return a python list with all them"""
a = []
fd = open(ifc,"r")
for i in fd:
if not i.startswith("//"):#skip comment lines
a.append(i.rstrip('\n'))
return a
def rgb2html(col):
"""Converts a color: from (255,255,255) to #ffffff"""
r,g,b = col
return "#%x%x%x" % (r,g,b)
def html2rgb(col):
"""Converts a color: from #ffffff to (255,255,255)"""
s=col.strip('#')
r=int(s[:2],16)
g=int(s[2:4],16)
b=int(s[4:6],16)
return r,g,b
def nextColor():
"""Gets next html color from color list"""
col = nextColor.array[nextColor.counter]
nextColor.counter +=1
return col
def isNextColor():
"""Is there another color or list is over?"""
return nextColor.counter<isNextColor.colorslenght
def isPageEnded(y,YSIZE):
"""Is there enough room to draw another square?"""
return (y+100)>=YSIZE
def newPage(XSIZE,YSIZE):
"""Returns a new image"""
return gimp.Image(XSIZE,YSIZE,RGB)
def createImage(color,text):
"""Draws a square filled with color and white color text. It works!"""
gimp.set_foreground((255,255,255))#text color
gimp.set_background(color) #background color
image = gimp.Image(100,100,RGB)
back = gimp.Layer(image,"font",100,100,RGB_IMAGE,100,NORMAL_MODE)
image.add_layer(back,1)
back.fill(BACKGROUND_FILL)
lay = back.copy()
lay.name = "font"
image.add_layer(lay,0)
lay = pdb.gimp_text_fontname(image,None,2,100/4,text,2,True,18,PIXELS,"Sans")
image.merge_down(lay, NORMAL_MODE)
image.flatten()
return image
def drawRect(image,x,y):
"""Here I'd like to copy the result of createImage at current x,y position of current image. It doesn't work!"""
text = nextColor()
color = html2rgb(text)
img = createImage(color,text)
drawable = pdb.gimp_image_active_drawable(image)
image.disable_undo()
pdb.gimp_selection_none(image)
pdb.gimp_image_select_rectangle(image, 2, x, y, 100, 100)
if pdb.gimp_edit_named_copy_visible(img, "buffer"):
floating_sel = pdb.gimp_edit_named_paste(drawable, "buffer", TRUE)
pdb.gimp_selection_none(image)
image.flatten()
gimp.Display(image)#to debug
image.enable_undo()
def savePage(image,directory,filename):
"""Saves composed image to filename"""
drawable = pdb.gimp_image_active_drawable(image)
pdb.file_png_save(image, drawable, directory+"\\"+filename, filename, 0,9,1,0,0,1,1)
def draw(ifile,savedir,prefix):
"""Main method. it manage page's room, slicing it in several 100x100 squares"""
YSIZE = 1000
XSIZE = 1000
x = y = pc = 0
colorArray = readColors(ifile)
nextColor.counter = 0
nextColor.array = colorArray
isNextColor.colorslenght = len(colorArray)
pdb.gimp_context_push()
image = newPage(XSIZE,YSIZE)
while(isNextColor()):
drawRect(image,x,y)
x += 100 # move to next column
if x+100>=XSIZE:#move to next row
x = 0
y += 100
if isPageEnded(y,YSIZE):
savePage(image,savedir,prefix+str(pc)+".png")
gimp.Display(image)#to debug
pc += 1
image = newPage(XSIZE,YSIZE)
x = 0
y = 0
savePage(image,savedir,prefix+str(pc)+".png")#save last page
pdb.gimp_context_pop()
ifc = '<path to color list file>\\colors.txt'
ofc = '<path to output directory>\\palette'
prefix = 'table' #prefix for each file(i.e.: table0.png, table1.png...)
draw(ifc,ofc,prefix) #main method call
My current problem is with drawRect method. I can't copy image returned by createImage method at coords x,y of bigger image in drawRect method. In drawRect method I tried to used gimp's "copy into selection": select an area, and paste in it stuff copied from another image. But I have a trouble with layers and I can't get image copied at right position.
Just for completeness this are few lines from ifc file:
#b6ffff
#f079f3
#9979f3
#79c2f3
#7a79f3
#79f380
#f3799a
Thanks in advance for any help.
Alberto
Maybe it could be useful for someone else (it must be saved as "draw-colors.py" and copied to GIMP 2/lib/gimp/2.0/plug-ins folder):
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from gimpfu import *
def readColors(ifile):
"""Read colors from input file and return a python list with all them"""
a = []
fd = open(ifile,"r")
for i in fd:
if not i.startswith('//'):
a.append(i)
return a
def rgb2html(col):
"""Converts a color: from (255,255,255) to #ffffff"""
r,g,b = col
return "#%x%x%x" % (r,g,b)
def html2rgb(col):
"""Converts a color: from #ffffff to (255,255,255)"""
s=col.strip('#')
r=int(s[:2],16)
g=int(s[2:4],16)
b=int(s[4:6],16)
return r,g,b
def nextColor():
"""Gets next html color from color list"""
col = html2rgb(nextColor.array[nextColor.counter])
nextColor.counter +=1
return col
def isNextColor():
"""Is there another color or list is over?"""
return nextColor.counter<isNextColor.colorslenght
def isPageEnded(y,sizey):
"""Is there enough room to draw another square?"""
return (y+100)>=sizey
def newPage(sizex,sizey):
"""Returns a new image"""
image = pdb.gimp_image_new(sizex, sizey, RGB)
layer = pdb.gimp_layer_new(image, sizex, sizey, RGB, "layer", 0, 0)
pdb.gimp_image_add_layer(image, layer, 0)
drw = pdb.gimp_image_active_drawable(image)
pdb.gimp_context_set_background((255,255,255))
pdb.gimp_drawable_fill(drw, BACKGROUND_FILL)
pdb.gimp_context_set_brush('Circle (01)')
return image
def savePage(image,filename):
"""Saves composed image to filename"""
layers = image.layers
last_layer = len(layers)-1
try:
disable=pdb.gimp_image_undo_disable(image)
pdb.gimp_layer_add_alpha(layers[0])
pdb.plug_in_colortoalpha(image,image.active_layer,(0,0,0))
layer = pdb.gimp_image_merge_visible_layers(image, 1)
enable = pdb.gimp_image_undo_enable(image)
pdb.file_png_save(image, image.active_layer, filename, filename, 0,9,1,0,0,1,1)
except Exception as e:
raise e
def drawRect(x,y,color,image):
"""draw a single square"""
text = rgb2html(color)
pdb.gimp_image_select_rectangle(image, 2, x, y, 100, 100)
pdb.gimp_context_set_background(color)
pdb.gimp_edit_fill(image.active_layer, 1)
try:
text_layer = pdb.gimp_text_fontname(image, None, x, y+(100/2), text, 2, 1, 18, 0, "Sans")
pdb.gimp_image_merge_down(image, text_layer, 0)
except Exception as e:
raise e
def draw(ifile,odir,prefix,sizex,sizey):
"""Main method. it manage page's room, slicing it in several 100x100 squares"""
colorArray = readColors(ifile)
nextColor.counter = 0
nextColor.array = colorArray
isNextColor.colorslenght = len(colorArray)
pc = x = y = 0
image = newPage(sizex,sizey)
try:
while(isNextColor()):
pdb.gimp_context_push()
drawRect(x,y,nextColor(),image)
x += 100#cambia colonna
if x+100>=sizex:#cambia riga
x = 0
y += 100
if isPageEnded(y,sizey):#salva pagina
savePage(image,odir+'\\'+prefix+str(pc)+".png")
pc += 1
image = newPage(sizex,sizey)
x = y = 0
savePage(image,odir+'\\'+prefix+str(pc)+".png")
pdb.gimp_context_pop()
except Exception as e:
raise e
register(
"draw-colors",
N_("Create a color map from a text color file"),
"Create a color map from a text color file",
"Alberto",
"#Copyright Alberto 2014",
"2014/10/21",
N_("Draw Colors..."),
"",
[
(PF_FILE, "ifile", N_("Color input file:"), 'default\\input\\colorfile\\path\\colorlist.txt'),
(PF_DIRNAME, "odir", N_("Path for png export:"), 'default\\output\\path'),
(PF_STRING, "prefix", N_("Filename prefix for export:"), "table"),
(PF_INT8, "sizex", N_("Image's x size:"), 1024),
(PF_INT8, "sizey", N_("Image's y size:"), 1024)
],
[],
draw, #main method call
menu="<Image>/Filters/Alberto",
domain=("gimp20-python", gimp.locale_directory)
)
main()
Output example:
I'm trying to implement colour cycling on my text in Python, ie i want it to cycle through the colour of every character typed (amongst other effects) My progress so far has been hacked together from an ansi colour recipe improvement suggestions welcomed.
I was also vaguely aware of, but never used: termcolor, colorama, curses
during the hack i managed to make the attributes not work (ie reverse blink etc) and its not perfect probably mainly because I dont understand these lines properly:
cmd.append(format % (colours[tmpword]+fgoffset))
c=format % attrs[tmpword] if tmpword in attrs else None
if anyone can clarify that a bit, I would appreciate it. this runs and does something, but its not quite there. I changed the code so instead of having to separate colour commands from your string you can include them.
#!/usr/bin/env python
'''
"arg" is a string or None
if "arg" is None : the terminal is reset to his default values.
if "arg" is a string it must contain "sep" separated values.
if args are found in globals "attrs" or "colors", or start with "#" \
they are interpreted as ANSI commands else they are output as text.
#* commands:
#x;y : go to xy
# : go to 1;1
## : clear screen and go to 1;1
#[colour] : set foreground colour
^[colour] : set background colour
examples:
echo('#red') : set red as the foreground color
echo('#red ^blue') : red on blue
echo('#red #blink') : blinking red
echo() : restore terminal default values
echo('#reverse') : swap default colors
echo('^cyan #blue reverse') : blue on cyan <=> echo('blue cyan)
echo('#red #reverse') : a way to set up the background only
echo('#red #reverse #blink') : you can specify any combinaison of \
attributes in any order with or without colors
echo('#blink Python') : output a blinking 'Python'
echo('## hello') : clear the screen and print 'hello' at 1;1
colours:
{'blue': 4, 'grey': 0, 'yellow': 3, 'green': 2, 'cyan': 6, 'magenta': 5, 'white': 7, 'red': 1}
'''
'''
Set ANSI Terminal Color and Attributes.
'''
from sys import stdout
import random
import sys
import time
esc = '%s['%chr(27)
reset = '%s0m'%esc
format = '1;%dm'
fgoffset, bgoffset = 30, 40
for k, v in dict(
attrs = 'none bold faint italic underline blink fast reverse concealed',
colours = 'grey red green yellow blue magenta cyan white'
).items(): globals()[k]=dict((s,i) for i,s in enumerate(v.split()))
bpoints = ( " [*] ", " [!] ", )
def echo(arg=None, sep=' ', end='\n', rndcase=True, txtspeed=0.03, bnum=0):
cmd, txt = [reset], []
if arg:
if bnum != 0:
sys.stdout.write(bpoints[bnum-1])
# split the line up into 'sep' seperated values - arglist
arglist=arg.split(sep)
# cycle through arglist - word seperated list
for word in arglist:
if word.startswith('#'):
### First check for a colour command next if deals with position ###
# go through each fg and bg colour
tmpword = word[1:]
if tmpword in colours:
cmd.append(format % (colours[tmpword]+fgoffset))
c=format % attrs[tmpword] if tmpword in attrs else None
if c and c not in cmd:
cmd.append(c)
stdout.write(esc.join(cmd))
continue
# positioning (starts with #)
word=word[1:]
if word=='#':
cmd.append('2J')
cmd.append('H')
stdout.write(esc.join(cmd))
continue
else:
cmd.append('%sH'%word)
stdout.write(esc.join(cmd))
continue
if word.startswith('^'):
### First check for a colour command next if deals with position ###
# go through each fg and bg colour
tmpword = word[1:]
if tmpword in colours:
cmd.append(format % (colours[tmpword]+bgoffset))
c=format % attrs[tmpword] if tmpword in attrs else None
if c and c not in cmd:
cmd.append(c)
stdout.write(esc.join(cmd))
continue
else:
for x in word:
if rndcase:
# thankyou mark!
if random.randint(0,1):
x = x.upper()
else:
x = x.lower()
stdout.write(x)
stdout.flush()
time.sleep(txtspeed)
stdout.write(' ')
time.sleep(txtspeed)
if txt and end: txt[-1]+=end
stdout.write(esc.join(cmd)+sep.join(txt))
if __name__ == '__main__':
echo('##') # clear screen
#echo('#reverse') # attrs are ahem not working
print 'default colors at 1;1 on a cleared screen'
echo('#red hello this is red')
echo('#blue this is blue #red i can ^blue change #yellow blah #cyan the colours in ^default the text string')
print
echo()
echo('default')
echo('#cyan ^blue cyan blue')
print
echo()
echo('#cyan this text has a bullet point',bnum=1)
print
echo('#yellow this yellow text has another bullet point',bnum=2)
print
echo('#blue this blue text has a bullet point and no random case',bnum=1,rndcase=False)
print
echo('#red this red text has no bullet point, no random case and no typing effect',txtspeed=0,bnum=0,rndcase=False)
# echo('#blue ^cyan blue cyan')
#echo('#red #reverse red reverse')
# echo('yellow red yellow on red 1')
# echo('yellow,red,yellow on red 2', sep=',')
# print 'yellow on red 3'
# for bg in colours:
# echo(bg.title().center(8), sep='.', end='')
# for fg in colours:
# att=[fg, bg]
# if fg==bg: att.append('blink')
# att.append(fg.center(8))
# echo(','.join(att), sep=',', end='')
#for att in attrs:
# echo('%s,%s' % (att, att.title().center(10)), sep=',', end='')
# print
from time import sleep, strftime, gmtime
colist='#grey #blue #cyan #white #cyan #blue'.split()
while True:
try:
for c in colist:
sleep(.1)
echo('%s #28;33 hit ctrl-c to quit' % c,txtspeed=0)
echo('%s #29;33 hit ctrl-c to quit' % c,rndcase=False,txtspeed=0)
#echo('#yellow #6;66 %s' % strftime('%H:%M:%S', gmtime()))
except KeyboardInterrupt:
break
except:
raise
echo('#10;1')
print
should also mention that i have absolutely no idea what this line does :) - well i see that it puts colours into a dictionary object, but how it does it is confusing. not used to this python syntax yet.
for k, v in dict(
attrs = 'none bold faint italic underline blink fast reverse concealed',
colours = 'grey red green yellow blue magenta cyan white'
).items(): globals()[k]=dict((s,i) for i,s in enumerate(v.split()))
This is a rather convoluted code - but, sticking to you r question, about the lines:
cmd.append(format % (colours[tmpword]+fgoffset))
This expression appends to the list named cmd the interpolation of the string contained in the variable format with the result of the expression (colours[tmpword]+fgoffset))- which concatenates the code in the color table (colours) named by tmpword with fgoffset.
The format string contains '1;%dm' which means it expects an integer number, whcih will replace the "%d" inside it. (Python's % string substitution inherits from C's printf formatting) . You "colours" color table ont he other hand is built in a convoluted way I'd recomend in no code, setting directly the entry in "globals" for it - but let's assume it does have the correct numeric value for each color entry. In that case, adding it to fgoffset will generate color codes out of range (IRCC, above 15) for some color codes and offsets.
Now the second line in which you are in doubt:
c=format % attrs[tmpword] if tmpword in attrs else None
This if is just Python's ternary operator - equivalent to the C'ish expr?:val1: val2
It is equivalent to:
if tmpword in attrs:
c = format % attrs[tmpword]
else:
c = format % None
Note that it has less precedence than the % operator.
Maybe you would prefer:
c= (format % attrs[tmpword]) if tmpword in attrs else ''
instead