I was looking for a way to load a ttf file and print text with that font. While looking for some information, I found this question: load a ttf font with the Windows API
In that question they recommend adding a private font with AddFontResourceEx. But I didn't find any way to access such function with pywin32 module and ctypes.windll. Is there any way to access this function? Or failing that, another way to print text with a ttf font without using Pillow???
Next, I will leave a code so you can do the tests:
import win32print
import win32gui
import win32ui
hprinter = win32print.OpenPrinter("Microsoft Print to Pdf")
devmode = win32print.GetPrinter(hprinter, 2)["pDevMode"]
hdc = win32gui.CreateDC("WINSPOOL", printer, devmode)
dc = win32ui.CreateDCFromHandle(Self.hdc)
Edit
I managed to access the function with
ctypes.windll.gdi32.AddFontResourceExA
But now I want to access the FR_PRIVATE constant. How can I do it?
Edit 2
I found out that the function doesn't work even without that constant.
I adapted the code from this answer and got the answer!
I will put the code below:
def add_font_file(file):
FR_PRIVATE = 0x10
file = ctypes.byref(ctypes.create_unicode_buffer(file))
font_count = gdi32.AddFontResourceExW(file, FR_PRIVATE, 0)
if(font_count == 0):
raise RuntimeError("Error durante la carga de la fuente.")
In case the original link goes down, the original code was as follows:
from ctypes import windll, byref, create_unicode_buffer, create_string_buffer
FR_PRIVATE = 0x10
FR_NOT_ENUM = 0x20
def loadfont(fontpath, private=True, enumerable=False):
'''
Makes fonts located in file `fontpath` available to the font system.
`private` if True, other processes cannot see this font, and this
font will be unloaded when the process dies
`enumerable` if True, this font will appear when enumerating fonts
See https://msdn.microsoft.com/en-us/library/dd183327(VS.85).aspx
'''
# This function was taken from
# https://github.com/ifwe/digsby/blob/f5fe00244744aa131e07f09348d10563f3d8fa99/digsby/src/gui/native/win/winfonts.py#L15
# This function is written for Python 2.x. For 3.x, you
# have to convert the isinstance checks to bytes and str
if isinstance(fontpath, str):
pathbuf = create_string_buffer(fontpath)
AddFontResourceEx = windll.gdi32.AddFontResourceExA
elif isinstance(fontpath, unicode):
pathbuf = create_unicode_buffer(fontpath)
AddFontResourceEx = windll.gdi32.AddFontResourceExW
else:
raise TypeError('fontpath must be of type str or unicode')
flags = (FR_PRIVATE if private else 0) | (FR_NOT_ENUM if not enumerable else 0)
numFontsAdded = AddFontResourceEx(byref(pathbuf), flags, 0)
return bool(numFontsAdded)
Related
Ive seen answers that finds the user's path, and then concatenating it with desktop, Such as:
desktop = os.path.expanduser("~/Desktop")
and
desktop = os.path.join(os.path.join(os.environ['USERPROFILE']), 'Desktop')
However it doesn't work when the device has non-default extensions:
C:\\Users\\NAME\\OneDrive\\Desktop
or non-english extension:
C:\\Users\\NAME\\OneDrive\\桌面
I ended up doing this as an emergency response:
possible_desktop_ext = ['Desktop', 'OneDrive\\Desktop', 'OneDrive\\桌面']
I can definitely see the list expanding exponentially in the future, and I don't really like the feeling of doing this every time I find a new extension.
So what is the most reliable way of retrieving the desktop's path?
This is adapted from https://stackoverflow.com/a/626927/5987, I urge you to go to it and give it the recognition it deserves.
import ctypes
from ctypes import wintypes, windll
CSIDL_DESKTOP = 0
_SHGetFolderPath = windll.shell32.SHGetFolderPathW
_SHGetFolderPath.argtypes = [wintypes.HWND,
ctypes.c_int,
wintypes.HANDLE,
wintypes.DWORD, wintypes.LPCWSTR]
path_buf = ctypes.create_unicode_buffer(wintypes.MAX_PATH)
result = _SHGetFolderPath(0, CSIDL_DESKTOP, 0, 0, path_buf)
print(path_buf.value)
After trying to break down code from GitHub and find any youtube videos that talk about this I'm starting to give up, so I'm hoping one of you can please help me. All I want to be able to do is monitor a games memory addresses value. For example, let's say in the game Minecraft the health value and the memory address is:
Address: 001F6498
Value: 20
How do I turn this value into a variable in Python?
Code Thought Process:
import pywin32
pid = 5601
address = 001F6498
ReadProcessMemory(pid, address):
print(Value)
#In this example i would like it to print 20
You need to get a handle to the process first. Here is some code that does so using OpenProcess() FindWindow() and GetWindowThreadProcessId() to get the handle to the process. Also included is a little function to properly read the correct size variable and store it correctly. This method can be used to read pointers, utilizing "i" to denote an integer type.
import win32api
import win32gui
import win32process
from ctypes import *
from pymem import *
PROCESS_ALL_ACCESS = 0x1F0FFF
ReadProcessMemory = windll.kernel32.ReadProcessMemory
def read_memory(procId, address, type):
buffer = (ctypes.c_byte * getlenght(type))()
bytesRead = ctypes.c_ulonglong(0)
readlenght = getlenght(type)
ReadProcessMemory(procId, address, buffer, readlenght, byref(bytesRead))
return struct.unpack(type, buffer)[0]
hWnd = win32gui.FindWindow(0, ("WINDOW NAME HERE"))
pid=win32process.GetWindowThreadProcessId(hWnd)
handle = pymem.Pymem()
handle.open_process_from_id(pid[1])
procBaseAddress = handle.process_base
hProc = windll.kernel32.OpenProcess(PROCESS_ALL_ACCESS, 0, pid[1])
value = ReadProcessMemory(hProc, ADDRESS_OF_VARIABLE_TO_READ, "i")
print(value)
Credits to a friend, puppetmaster, who taught me how to do this
im working on a little solitär trainer. I don't know why the function ReadProcessMemory doesn't work. Normally it returns a False or True but in that case nothing. The GetlastError() gives me the Errorcode 6.
#-*- coding: cp1252 -*-
import ctypes, win32ui, win32process ,win32api
PROCESS_ALL_ACCESS = 0x1F0FFF
HWND = win32ui.FindWindow(None,"Solitär").GetSafeHwnd()
print(HWND)
PID = win32process.GetWindowThreadProcessId(HWND)[1]
print(PID)
PROCESS = win32api.OpenProcess(PROCESS_ALL_ACCESS,0,PID).handle
rPM = ctypes.windll.kernel32.ReadProcessMemory
wPM = ctypes.windll.kernel32.WriteProcessMemory
ADDRESS1 = 0x00E97074
ADDRESS2 = ctypes.create_string_buffer(64)
pi = ctypes.pointer(ADDRESS2)
rPM(PROCESS,ADDRESS1,ADDRESS2,64,0)
print(ADDRESS2)
x=ctypes.windll.kernel32.GetLastError()
print(x)
Check the community comment to the MSDN ReadProcessMemory page, quote(sic):
W7 wont run read process memory
You may need to check your access permissions for "SE_DEBUG_NAME" for the current processes token. If not enabled. Enabled it. This must be done as administrator of course.
Also fully declare the return types and use the use_last_error parameter, where ctypes will cache the GetLastError() value internally directly after the call. Otherwise, it may be incorrect. If you are on a 64-bit system, SIZE_T and pointers are 64-bit values so ctypes needs to know the types to set up the stack correctly for the call.
...
from ctypes import wintypes
...
rPM = ctypes.WinDLL('kernel32',use_last_error=True).ReadProcessMemory
rPM.argtypes = [wintypes.HANDLE,wintypes.LPCVOID,wintypes.LPVOID,ctypes.c_size_t,ctypes.POINTER(ctypes.c_size_t)]
rPM.restype = wintypes.BOOL
wPM = ctypes.WinDLL('kernel32',use_last_error=True).WriteProcessMemory
wPM.argtypes = [wintypes.HANDLE,wintypes.LPVOID,wintypes.LPCVOID,ctypes.c_size_t,ctypes.POINTER(ctypes.c_size_t)]
wPM.restype = wintypes.BOOL
ADDRESS1 = 0x00E97074
ADDRESS2 = ctypes.create_string_buffer(64)
bytes_read = ctypes.c_size_t()
print(rPM(PROCESS,ADDRESS1,ADDRESS2,64,ctypes.byref(bytes_read)))
print(ctypes.get_last_error())
Also, FYI, even with all the fixes I get the same error value, but I didn't go through the trouble of enabling SE_DEBUG_NAME.
SOLVED
The following line is the issue:
PROCESS = win32api.OpenProcess(PROCESS_ALL_ACCESS,0,PID).handle
win32api.OpenProcess returns a temporary PyHANDLE that gets destroyed and closes the handle after the handle is retrieved.
The solution is to use:
PROCESS = win32api.OpenProcess(PROCESS_ALL_ACCESS,0,PID)
...
rPM(PROCESS.handle,ADDRESS1,ADDRESS2,64,0)
PROCESS then holds the PyHANDLE object and the handle remains valid.
I'm trying to modify the simple python script provided with my Pipsta Printer so that instead of printing a single line of text, it prints out a list of things.
I know there are probably better ways to do this, but using the script below, could somebody please tell me what changes I need to make around the "txt = " part of the script, so that I can print out a list of items and not just one item?
Thanks.
# BasicPrint.py
# Copyright (c) 2014 Able Systems Limited. All rights reserved.
'''This simple code example is provided as-is, and is for demonstration
purposes only. Able Systems takes no responsibility for any system
implementations based on this code.
This very simple python script establishes USB communication with the Pipsta
printer sends a simple text string to the printer.
Copyright (c) 2014 Able Systems Limited. All rights reserved.
'''
import argparse
import platform
import sys
import time
import usb.core
import usb.util
FEED_PAST_CUTTER = b'\n' * 5
USB_BUSY = 66
# NOTE: The following section establishes communication to the Pipsta printer
# via USB. YOU DO NOT NEED TO UNDERSTAND THIS SECTION TO PROGRESS WITH THE
# TUTORIALS! ALTERING THIS SECTION IN ANY WAY CAN CAUSE A FAILURE TO COMMUNICATE
# WITH THE PIPSTA. If you are interested in learning about what is happening
# herein, please look at the following references:
#
# PyUSB: http://sourceforge.net/apps/trac/pyusb/
# ...which is a wrapper for...
# LibUSB: http://www.libusb.org/
#
# For full help on PyUSB, at the IDLE prompt, type:
# >>> import usb
# >>> help(usb)
# 'Deeper' help can be trawled by (e.g.):
# >>> help(usb.core)
#
# or at the Linux prompt, type:
# pydoc usb
# pydoc usb.core
PIPSTA_USB_VENDOR_ID = 0x0483
PIPSTA_USB_PRODUCT_ID = 0xA053
def parse_arguments():
'''Parse the arguments passed to the script looking for a font file name
and a text string to print. If either are mssing defaults are used.
'''
txt = 'Hello World from Pipsta!'
parser = argparse.ArgumentParser()
parser.add_argument('text', help='the text to print',
nargs='*', default=txt.split())
args = parser.parse_args()
return ' '.join(args.text)
def main():
"""The main loop of the application. Wrapping the code in a function
prevents it being executed when various tools import the code.
"""
if platform.system() != 'Linux':
sys.exit('This script has only been written for Linux')
# Find the Pipsta's specific Vendor ID and Product ID
dev = usb.core.find(idVendor=PIPSTA_USB_VENDOR_ID,
idProduct=PIPSTA_USB_PRODUCT_ID)
if dev is None: # if no such device is connected...
raise IOError('Printer not found') # ...report error
try:
# Linux requires USB devices to be reset before configuring, may not be
# required on other operating systems.
dev.reset()
# Initialisation. Passing no arguments sets the configuration to the
# currently active configuration.
dev.set_configuration()
except usb.core.USBError as ex:
raise IOError('Failed to configure the printer', ex)
# The following steps get an 'Endpoint instance'. It uses
# PyUSB's versatile find_descriptor functionality to claim
# the interface and get a handle to the endpoint
# An introduction to this (forming the basis of the code below)
# can be found at:
cfg = dev.get_active_configuration() # Get a handle to the active interface
interface_number = cfg[(0, 0)].bInterfaceNumber
# added to silence Linux complaint about unclaimed interface, it should be
# release automatically
usb.util.claim_interface(dev, interface_number)
alternate_setting = usb.control.get_interface(dev, interface_number)
interface = usb.util.find_descriptor(
cfg, bInterfaceNumber=interface_number,
bAlternateSetting=alternate_setting)
usb_endpoint = usb.util.find_descriptor(
interface,
custom_match=lambda e:
usb.util.endpoint_direction(e.bEndpointAddress) ==
usb.util.ENDPOINT_OUT
)
if usb_endpoint is None: # check we have a real endpoint handle
raise IOError("Could not find an endpoint to print to")
# Now that the USB endpoint is open, we can start to send data to the
# printer.
# The following opens the text_file, by using the 'with' statemnent there is
# no need to close the text_file manually. This method ensures that the
# close is called in all situation (including unhandled exceptions).
txt = parse_arguments()
usb_endpoint.write(b'\x1b!\x00')
# Print a char at a time and check the printers buffer isn't full
for x in txt:
usb_endpoint.write(x) # write all the data to the USB OUT endpoint
res = dev.ctrl_transfer(0xC0, 0x0E, 0x020E, 0, 2)
while res[0] == USB_BUSY:
time.sleep(0.01)
res = dev.ctrl_transfer(0xC0, 0x0E, 0x020E, 0, 2)
usb_endpoint.write(FEED_PAST_CUTTER)
usb.util.dispose_resources(dev)
# Ensure that BasicPrint is ran in a stand-alone fashion (as intended) and not
# imported as a module. Prevents accidental execution of code.
if __name__ == '__main__':
main()
Pipsta uses linux line-feed ('\n', 0x0A, 10 in decimal) to mark a new line. For a quick test change BasicPrint.py as follows:
#txt = parse_arguments()
txt = 'Recipt:\n========\n1. food 1 - 100$\n2. drink 1 - 200$\n\n\n\n\n'
usb_endpoint.write(b'\x1b!\x00')
for x in txt:
usb_endpoint.write(x)
res = dev.ctrl_transfer(0xC0, 0x0E, 0x020E, 0, 2)
while res[0] == USB_BUSY:
time.sleep(0.01)
res = dev.ctrl_transfer(0xC0, 0x0E, 0x020E, 0, 2)
I commented out parameter parsing and injected a test string with multi line content.
I write a snippet using ctypes and tesseract 3.0.2 referring to the example:
import ctypes
from PIL import Image
libname = '/opt/tesseract/lib/libtesseract.so.3.0.2'
tesseract = ctypes.cdll.LoadLibrary(libname)
api = tesseract.TessBaseAPICreate()
rc = tesseract.TessBaseAPIInit3(api, "", 'eng')
filename = '/opt/ddl.ddl.exp654.png'
text_out = tesseract.TessBaseAPIProcessPages(api, filename, None, 0)
result_text = ctypes.string_at(text_out)
print result_text
It passes filename as a parameter, I have no idea to call which method in API to pass the raw data like:
tesseract.TessBaseAPIWhichMethod(api, open(filename).read())
I can't say for sure but I don't think you can pass complex python objects to that specific API, it won't know how to handle them. Your best bet would to be to look at a wrapper like http://code.google.com/p/python-tesseract/ which will allow you to use file buffers
import tesseract
api = tesseract.TessBaseAPI()
api.Init(".","eng",tesseract.OEM_DEFAULT)
api.SetVariable("tessedit_char_whitelist", "0123456789abcdefghijklmnopqrstuvwxyz")
api.SetPageSegMode(tesseract.PSM_AUTO)
mImgFile = "eurotext.jpg"
mBuffer=open(mImgFile,"rb").read()
result = tesseract.ProcessPagesBuffer(mBuffer,len(mBuffer),api) #YAY for buffers.
print "result(ProcessPagesBuffer)=",result
Edit
http://code.google.com/p/python-tesseract/source/browse/python-tesseract-0.7.4/debian/python-tesseract/usr/share/pyshared/tesseract.py might provide you with the insight that you need.
...
Acutally if you don't mind what happens when you replace
text_out = tesseract.TessBaseAPIProcessPages(api, filename, None, 0)
with
text_out = tesseract.ProcessPagesBuffer(mBuffer,len(mBuffer),api)