Copy PIL/PILLOW Image to Windows Clipboard - python

I've seen this question and i followed every step, changing the code to satisfy my requirements, that are Python3, Pillow, and ctypes. The less libraries, the better.
import ctypes
from PIL import ImageGrab, Image
from io import BytesIO
user32 = ctypes.windll.user32
img = ImageGrab.grab()
output = BytesIO()
img.convert("RGB").save(output, "BMP")
data = output.getvalue()[14:]
output.close()
user32.OpenClipboard()
user32.EmptyClipboard()
user32.SetClipboardData(user32.CF_DIB, data)
user32.CloseClipboard()
That is the stripped code from my script that, i think, is the same code in the question ported to my requirements. When executed, it should copy the current desktop to the clipboard. I get this instead:
File "C:\Users\Gcq\Documents\python\Screen\Screen.py", line 132, in shot
user32.OpenClipboard()
ValueError: Procedure probably called with not enough arguments (4 bytes missing)
I'm sorry i'm asking such a (probably) easy question here, but i really don't know what is failing, and ctypes is not my thing.

The example uses pywin32, which is Python wrapper around Win32 API that hides some low level details you need to take care yourself of if you want to use ctypes.
Here is how you do it using ctypes, it adds a functionally of creating globally allocated buffer and copy the data into that buffer:
#!python
from PIL import Image
#from cStringIO import StringIO
from io import BytesIO
from ctypes import *
from ctypes.wintypes import *
HGLOBAL = HANDLE
SIZE_T = c_size_t
GHND = 0x0042
GMEM_SHARE = 0x2000
GlobalAlloc = windll.kernel32.GlobalAlloc
GlobalAlloc.restype = HGLOBAL
GlobalAlloc.argtypes = [UINT, SIZE_T]
GlobalLock = windll.kernel32.GlobalLock
GlobalLock.restype = LPVOID
GlobalLock.argtypes = [HGLOBAL]
GlobalUnlock = windll.kernel32.GlobalUnlock
GlobalUnlock.restype = BOOL
GlobalUnlock.argtypes = [HGLOBAL]
CF_DIB = 8
OpenClipboard = windll.user32.OpenClipboard
OpenClipboard.restype = BOOL
OpenClipboard.argtypes = [HWND]
EmptyClipboard = windll.user32.EmptyClipboard
EmptyClipboard.restype = BOOL
EmptyClipboard.argtypes = None
SetClipboardData = windll.user32.SetClipboardData
SetClipboardData.restype = HANDLE
SetClipboardData.argtypes = [UINT, HANDLE]
CloseClipboard = windll.user32.CloseClipboard
CloseClipboard.restype = BOOL
CloseClipboard.argtypes = None
#################################################
image = Image.new("RGB", (200, 200), (255, 0, 0))
#output = StringIO()
output = BytesIO()
image.convert("RGB").save(output, "BMP")
data = output.getvalue()[14:]
output.close()
hData = GlobalAlloc(GHND | GMEM_SHARE, len(data))
pData = GlobalLock(hData)
memmove(pData, data, len(data))
GlobalUnlock(hData)
OpenClipboard(None)
EmptyClipboard()
SetClipboardData(CF_DIB, pData)
CloseClipboard()

Whew. Apparently the win32clipboard library does simplify some things when compared to ctypes. Your attempt to simply replace one with the other is far from correct.
So I booted up my Windows virtual machine, installed Pillow and rewrote your program, learning from two other answers:
import io
import ctypes
msvcrt = ctypes.cdll.msvcrt
kernel32 = ctypes.windll.kernel32
user32 = ctypes.windll.user32
from PIL import ImageGrab
img = ImageGrab.grab()
output = io.BytesIO()
img.convert('RGB').save(output, 'BMP')
data = output.getvalue()[14:]
output.close()
CF_DIB = 8
GMEM_MOVEABLE = 0x0002
global_mem = kernel32.GlobalAlloc(GMEM_MOVEABLE, len(data))
global_data = kernel32.GlobalLock(global_mem)
msvcrt.memcpy(ctypes.c_char_p(global_data), data, len(data))
kernel32.GlobalUnlock(global_mem)
user32.OpenClipboard(None)
user32.EmptyClipboard()
user32.SetClipboardData(CF_DIB, global_mem)
user32.CloseClipboard()

Related

Exception on using ctypes with tesserac-ocr TessPageIteratorBoundingBox

import ctypes
import os
os.putenv("PATH", r'C:\Program Files\Tesseract-OCR')
os.environ["TESSDATA_PREFIX"] = r'C:\Program Files\Tesseract-OCR\tessdata'
liblept = ctypes.cdll.LoadLibrary('liblept-5.dll')
pix = liblept.pixRead('test.png'.encode())
print(pix)
tesseractLib = ctypes.cdll.LoadLibrary('libtesseract-5.dll')
tesseractHandle = tesseractLib.TessBaseAPICreate()
tesseractLib.TessBaseAPIInit3(tesseractHandle, '.', 'eng')
tesseractLib.TessBaseAPISetImage2(tesseractHandle, pix)
# text_out = tesseractLib.TessBaseAPIGetUTF8Text(tesseractHandle)
# print(ctypes.string_at(text_out))
tessPageIterator = tesseractLib.TessResultIteratorGetPageIterator(tesseractHandle)
iteratorLevel = 3 # RIL_BLOCK, RIL_PARA, RIL_TEXTLINE, RIL_WORD, RIL_SYMBOL
tesseractLib.TessPageIteratorBoundingBox(tessPageIterator, iteratorLevel, ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0))
I got exceptions :
Traceback (most recent call last):
File "D:\BaiduYunDownload\programming\Python\CtypesOCR.py", line 25, in <module>
tesseractLib.TessPageIteratorBoundingBox(tessPageIterator, iteratorLevel, ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0), ctypes.c_int(0))
OSError: exception: access violation reading 0x00000018
So what's wrong ?
The aim of this program is to get bounding rectangle of each word. I know projects like tesserocr and PyOCR
P.S. Specifying the required argument types (function prototypes) for the DLL functions doesn't matter here. One could uncoment the commented lines and comment the last three lines to test it. I posted the question before , and it was closed for this reason
I solved my question by myself
import ctypes
import os
import io
os.putenv("PATH", r'C:\Program Files\Tesseract-OCR')
os.environ["TESSDATA_PREFIX"] = r'C:\Program Files\Tesseract-OCR\tessdata'
liblept = ctypes.cdll.LoadLibrary('liblept-5.dll')
pix = liblept.pixRead(b'test.png') # 必须encode
print(pix)
tesseractLib = ctypes.cdll.LoadLibrary('libtesseract-5.dll')
tesseractHandle = tesseractLib.TessBaseAPICreate()
tesseractLib.TessBaseAPIInit3(tesseractHandle, b'.', b'eng') # (TessBaseAPI* handle, const char* datapath,const char* language);
# from PIL import Image
# pixmap = Image.open("test.png")
# image = io.BytesIO()
# pixmap.save(image, 'png') # 没有什么类型,这里就任意指定个吧;For images created by the library itself (via a factory function, or by running a method on an existing image), this attribute is set to None.
# image.seek(0) # 要回到开始才行,不然后面requests读的时候会从结尾读,读不到数据
tesseractLib.TessBaseAPISetImage2(tesseractHandle, pix) # pixmap.tobytes("raw", "RGB")
# text_out = tesseractLib.TessBaseAPIGetUTF8Text(tesseractHandle)
# print(ctypes.string_at(text_out))
tesseractLib.TessBaseAPIRecognize(tesseractHandle, None) # 必须有,否则下面会出问题
tessResultIterator = tesseractLib.TessBaseAPIGetIterator(tesseractHandle) # TessResultIteratorGetPageIterator要用
tessPageIterator = tesseractLib.TessResultIteratorGetPageIterator(tessResultIterator)
wordLevel = 3 # RIL_BLOCK, RIL_PARA, RIL_TEXTLINE, RIL_WORD, RIL_SYMBOL
left = ctypes.c_int(0) # 这几个是要用来写入数据的,所以要构造出来 可写;byref() argument must be a ctypes instance, not 'int'
top = ctypes.c_int(0)
right = ctypes.c_int(0)
bottom = ctypes.c_int(0)
while True:
r = tesseractLib.TessPageIteratorBoundingBox(
tessPageIterator,
wordLevel,
ctypes.byref(left), # byref behaves similar to pointer(obj), but the construction is a lot faster.
ctypes.byref(top),
ctypes.byref(right),
ctypes.byref(bottom)
)
text_out = tesseractLib.TessResultIteratorGetUTF8Text(tessPageIterator, wordLevel)
print(ctypes.string_at(text_out), left.value, top.value, right.value, bottom.value)
if not tesseractLib.TessPageIteratorNext(tessPageIterator, wordLevel):
break

Windows Python Code not working on Linux Debian

The code generates a QR code and prints it, but It is not working on the Debian Os due to not supporting the imported libraries (win32print, Win32ui).
Can anyone tell me how to run it on the Debian without changing the whole code.
from random import randint
import win32print
import win32ui
from PIL import Image, ImageWin
from PIL._imaging import font
from PIL import ImageFont
from PIL import ImageDraw
HORZRES = 8
VERTRES = 10
LOGPIXELSX = 88
LOGPIXELSY = 90
PHYSICALWIDTH = 110
PHYSICALHEIGHT = 111
PHYSICALOFFSETX = 112
PHYSICALOFFSETY = 113
__author__ = 'masoodhussain'
import qrcode
import subprocess
import os
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=10,
border=4,
)
qr.add_data('Masooddkjfdlfs,kokdfds sddshfhkjshfljsdhkjfdrtyyhtfhfghgh3')
qr.make(fit=True)
"subprocess.call(['lp', 'foo.png'])"
printer_name = win32print.GetDefaultPrinter()
img = qr.make_image()
img.show()
random_number= randint(0,10000)
img.save('label_'+str(random_number)+'.png')
file_name = 'label_'+str(random_number)+'.png'
print(file_name)
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)
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)
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 ()
when I run the code by removing the unsupported libraries it gives an error on this part: error importing
import qrcode
I am trying to import whole folder for using there other files. In Windows it was working perfectly. Any help would be appreciated.Thanks
This code is equivalent to the code posted in Question.
from random import randint
import cups
from PIL import Image, ImageWin
from PIL._imaging import font
from PIL import ImageFont
from PIL import ImageDraw
__author__ = 'masoodhussain'
import qrcode
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=5,
border=2,
)
qr.add_data('localhost:5070productinfo')
qr.make(fit=True)
conn= cups.Connection()
printer_name = conn.getPrinters()
printer_name = printer_name.keys()[0]
printqueuelength = len(conn.getJobs())
img = qr.make_image()
img.show()
random_number= randint(0,10000)
img.save('label_'+str(random_number)+'.png')
file_name = 'label_'+str(random_number)+'.png'
print(file_name)
conn.printFile(printer_name,file_name,"Hello", options ={'media':'25x25mm'})
Important part is the installation of required libraries and changing your media to the required size.
Even if you install qrcode, your code will still fail because of the Windows specific library. You need to check on which system you are working and preferably put the whole print function in a separate function.
Here are some useful links: https://stackoverflow.com/a/1857/2776376 and https://pypi.python.org/pypi/pycups
import platform
if platform.system() = 'Linux':
import libcups
elif platform.system() = 'Windows':
import win32print
import win32ui
else:
print('Unsupported OS. Exiting....')
sys.exit(1)
def my_printer_function():
if platform.system() = 'Linux':
#now call the Linux printer
elif platform.system() = 'Windows':
#use your old Windows code

Get Associated Filetype Icon for a File

What I Want
I'm trying to write a function which takes in a filename and returns the icon of the application that is associated with the file's filetype on my system (which is Windows 7).
What I've Tried
I've seen this question, but the answer isn't giving me the details I need. I'm not very familiar with the ctypes module and I find the docs on the VC++ functions difficult to follow.
I also saw this question, but I get stuck on the first hurdle.
When I try:
import _winreg
_winreg.OpenKey(_winreg.HKEY_CURRENT_USER, 'Software\Microsoft\CurrentVersion\Explorer\FileExts')
It raises a WindowsError: [Error 2] The system cannot find the file specified
Even when I do
_winreg.OpenKey(_winreg.HKEY_CURRENT_USER, 'Software\Microsoft')
Which returns a PyHKEY object, any 'key' action I try perform on it raises a TypeError: The object is not a PyHKEY object
I've found an answer here
the code from the link is:
import win32ui
import win32gui
import win32con
import win32api
import cStringIO
import Image
tempDirectory = os.getenv("temp")
ico_x = win32api.GetSystemMetrics(win32con.SM_CXICON)
dst = cStringIO.StringIO()
large, small = win32gui.ExtractIconEx(path,0)
win32gui.DestroyIcon(small[0])
#creating a destination memory DC
hdc = win32ui.CreateDCFromHandle( win32gui.GetDC(0) )
hbmp = win32ui.CreateBitmap()
hbmp.CreateCompatibleBitmap(hdc, ico_x, ico_x)
hdc = hdc.CreateCompatibleDC()
hdc.SelectObject( hbmp )
#draw a icon in it
hdc.DrawIcon( (0,0), large[0] )
win32gui.DestroyIcon(large[0])
#convert picture
hbmp.SaveBitmapFile( hdc, tempDirectory + "\Icontemp.bmp")
im = Image.open(tempDirectory + "\Icontemp.bmp")
im.save(dst, "JPEG")
dst.seek(0)
os.remove(tempDirectory + "\Icontemp.bmp")
return dst.read()
Here's some working py2 code for you. Unfortunately I definitely do NOT understand everything going on here, but I can at least say that it definitely does work!
import win32ui
import win32gui
import win32con
import win32api
def save_icon(exe_file, out_file):
ico_x = win32api.GetSystemMetrics(win32con.SM_CXICON)
ico_y = win32api.GetSystemMetrics(win32con.SM_CYICON)
large, small = win32gui.ExtractIconEx(exe_file, 0)
win32gui.DestroyIcon(large[0])
hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
hbmp = win32ui.CreateBitmap()
hbmp.CreateCompatibleBitmap( hdc, ico_x, ico_y )
hdc = hdc.CreateCompatibleDC()
hdc.SelectObject( hbmp )
hdc.DrawIcon( (0,0), small[0] )
hbmp.SaveBitmapFile( hdc, out_file )

How to extract 128x128 icon bitmap data from EXE in python

I'm trying to extract icons from .exe files in windows using win32gui. I found the functionalities ExtractIconEx() and ExtractIcon().
I am able to get Icons of size 32x32 or 16x16 only from the above functionalities. the following link only answers way to extract 32x32 images.
How to extract 32x32 icon bitmap data from EXE and convert it into a PIL Image object?
I need to extract icons of size either 128x128 or greater than that.Any ideas on how to extract the largersize icons from exe files?
I've made some researches and also post it. If you would like just see the result code (I hope it's exactly what you ask) you could find it after the "horizontal rule" below.
First I tried to use the next code to determine what icon sizes stored in the resources of the file:
# Using LoadLibrary (rather than CreateFile) is required otherwise
# LoadResource, FindResource and others will fail
PATH = ... # Valid file path
hlib = win32api.LoadLibrary(PATH)
# This loop should print sizes of resources icons
icon_names = win32api.EnumResourceNames(hlib, win32con.RT_ICON)
for icon_name in icon_names:
rec = win32api.LoadResource(hlib, win32con.RT_ICON, icon_name)
hicon = win32gui.CreateIconFromResource(rec, True)
info = win32gui.GetIconInfo(hicon)
bminfo = win32gui.GetObject(info[3])
print("%2d: 0x%08X -> %d %d " % (icon_name, hicon, bminfo.bmWidth, bminfo.bmHeight))
While file contains only 16x16 and 32x32 pixels icons everything will be Ok, here the output for Windows XP calculator:
1: 0x0093051B -> 32 32
2: 0x005B0513 -> 32 32
3: 0x007004CB -> 32 32
4: 0x002E04C9 -> 32 32
5: 0x033A04C5 -> 32 32
6: 0x00780487 -> 32 32
7: 0x0052045D -> 32 32
8: 0x055D053D -> 32 32
Once I've tried on file with large icon I've get the exception:
Traceback (most recent call last):
File "extract_icon.py", line 50, in <module>
hicon = win32gui.CreateIconFromResource(rec, True)
pywintypes.error: (0, 'CreateIconFromResource', 'No error message is available')
After some researches I've figured out that large icon stored not in ico format but in png (for my case).
Of course I don't know what exactly your .exe file (it's internals) but after I've analyze several .exe files that I have located in my PC I've find out that icons large than 32x32 or 16x16 pixels most probably represented by mean of .png files (you could check it using e.g. PE Explorer, trial-version existed).
So to read image from resources I've used the guide on C++. The main goal here is to obtain pointer to the image resource real data and copy it to the Python buffer. And the finish step is save it to the file (I think you could translate it to PIL by yourself).
COMPLETE CODE TO READ LARGE RESOURCE:
# Use wchar_t function version (FindResourceW rather than FindResourceA)
from __future__ import unicode_literals
# pywin32 imports
import pywintypes
import win32ui
import win32gui
import win32con
import win32api
import win32file
# ctypes configuring. pywin32 has no a lot of required functions
import ctypes
import ctypes.util
# memcpy used to copy data from resource storage to our buffer
libc = ctypes.CDLL(ctypes.util.find_library('c'))
libc.memcpy.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t]
libc.memcpy.restype = ctypes.c_char_p
# All Windows backslashes must be escaped to LoadLibrary worked correctly '\' -> '\\'
PATH = ...
# WARNING: Assumed that icon_name - VALID resource ID
# It can be determined in loop when enumerating resources:
# if exception at CreateIconFromResource raised than this code appropriate
# otherwise resource is standard icon and first code snippet can be used.
# If resources Id exactly known then it can be hardcoded as in this code
icon_name = 1
try:
hlib = win32api.LoadLibrary(PATH)
# This part almost identical to C++
hResInfo = ctypes.windll.kernel32.FindResourceW(hlib, icon_name, win32con.RT_ICON)
size = ctypes.windll.kernel32.SizeofResource(hlib, hResInfo)
rec = win32api.LoadResource(hlib, win32con.RT_ICON, icon_name)
mem_pointer = ctypes.windll.kernel32.LockResource(rec)
# And this is some differ (copy data to Python buffer)
binary_data = (ctypes.c_ubyte * size)()
libc.memcpy(binary_data, mem_pointer, size)
# Save it
with open("icon.png", "wb") as test_file:
test_file.write(bytearray(binary_data))
except pywintypes.error as error:
print "ERROR: %s" % error.strerror
raise
UPDATED:
Code to automatically look up non-icon resources and extract it to file named "Resource_XX":
# Same IMPORT's as previously should be used
# All Windows backslashes must be escaped to LoadLibrary worked correctly '\' -> '\\'
PATH = ...
def extract(rec):
try:
hicon = win32gui.CreateIconFromResource(rec, True)
except pywintypes.error as error:
# Check on appropriate error
if error.winerror != 6:
raise
print("Resource %2d isn't .ico, extract" % icon_name)
# This part almost identical to C++
hResInfo = ctypes.windll.kernel32.FindResourceW(hlib, icon_name, win32con.RT_ICON)
size = ctypes.windll.kernel32.SizeofResource(hlib, hResInfo)
mem_pointer = ctypes.windll.kernel32.LockResource(rec)
# And this is some differ (copy data to Python buffer)
binary_data = (ctypes.c_ubyte * size)()
libc.memcpy(binary_data, mem_pointer, size)
# Save it
with open("Resource_%s.png" % icon_name, "wb") as extract_file:
extract_file.write(bytearray(binary_data))
else:
info = win32gui.GetIconInfo(hicon)
bminfo = win32gui.GetObject(info[3])
print("Resource %2d is .ico: 0x%08X -> %d %d " %
(icon_name, hicon, bminfo.bmWidth, bminfo.bmHeight))
try:
hlib = win32api.LoadLibrary(PATH)
icon_names = win32api.EnumResourceNames(hlib, win32con.RT_ICON)
for icon_name in icon_names:
rec = win32api.LoadResource(hlib, win32con.RT_ICON, icon_name)
extract(rec)
except pywintypes.error as error:
print "ERROR: %s" % error.strerror
raise
I want to extract the default icon and the different sizs. Based on Alexei's answer and Audionautics' answer in the 32x32 thread, here is the code.
# Use wchar_t function version (FindResourceW rather than FindResourceA)
from __future__ import unicode_literals
# pywin32 imports
import win32con
import win32api
import win32file
import win32gui
import win32ui
import pywintypes
# ctypes configuring. pywin32 has no a lot of required functions
import ctypes
import ctypes.util
# memcpy used to copy data from resource storage to our buffer
libc = ctypes.CDLL(ctypes.util.find_library('c'))
libc.memcpy.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t]
libc.memcpy.restype = ctypes.c_char_p
# patch FindResourceW, ctypes.windll.kernel32.SizeofResource
FindResourceW = ctypes.windll.kernel32.FindResourceW
FindResourceW.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
FindResourceW.restype = ctypes.c_void_p
SizeofResource = ctypes.windll.kernel32.SizeofResource
SizeofResource.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
SizeofResource.restype = ctypes.c_size_t
# Using LoadLibrary (rather than CreateFile) is required otherwise
# LoadResource, FindResource and others will fail
PATH = "C:\\Program Files\\Internet Explorer\\iexplore.exe"
hlib = win32api.LoadLibraryEx(PATH, 0, 2)
# get icon groups, default is the first group
icon_groups = win32api.EnumResourceNames(hlib, win32con.RT_GROUP_ICON)
group_name = icon_groups[0]
print group_name
hRes = win32api.LoadResource(hlib, win32con.RT_GROUP_ICON, group_name)
mem_icon_dir = ctypes.windll.kernel32.LockResource(hRes)
# 32 bits color; 16 and 256 colors are too old
# iterate through the common sizes
icon_sizes = (16, 24, 32, 48, 96, 256)
for icon_size in icon_sizes:
icon_name = ctypes.windll.user32.LookupIconIdFromDirectoryEx(mem_icon_dir, True, icon_size, icon_size, 0x00000000);
hResInfo = FindResourceW(hlib, icon_name, win32con.RT_ICON)
size = ctypes.windll.kernel32.SizeofResource(hlib, hResInfo)
rec = win32api.LoadResource(hlib, win32con.RT_ICON, icon_name)
mem_icon = ctypes.windll.kernel32.LockResource(rec)
# And this is some differ (copy data to Python buffer)
binary_data = (ctypes.c_ubyte * size)()
libc.memcpy(binary_data, mem_icon, size)
hIconRet = ctypes.windll.user32.CreateIconFromResourceEx(binary_data, size, True, 0x00030000, 0, 0, 0x00000000);
info = win32gui.GetIconInfo(hIconRet)
bminfo = win32gui.GetObject(info[4])
# generate bitmap by drawing the icon
hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
hbmp = win32ui.CreateBitmap()
hbmp.CreateCompatibleBitmap(hdc, bminfo.bmWidth, bminfo.bmHeight)
hcdc = hdc.CreateCompatibleDC()
hcdc.SelectObject(hbmp)
win32gui.DrawIconEx(hcdc.GetHandleOutput(), 0, 0, hIconRet, bminfo.bmWidth, bminfo.bmHeight, 0, 0, 0x0003)
hbmp.SaveBitmapFile(hcdc, "icon-%03dx%03d-%05d-%03d.bmp" % (bminfo.bmWidth, bminfo.bmHeight, group_name, icon_name))
win32gui.DestroyIcon(hIconRet)

Python- Saving/Accessing file extension icons and using them in a Tkinter program

I'm currently trying to figure out how to create some code which will take the input of a file extension like '.png' and return the icon associated with that filetype on the system.
I'm using python 2.7.6 and using Windows 8. I've been looking for code for this for hours to things close to it by saving images from .exe files but not finding the file extension in the registry and saving it.
I have found some code that works and allows me to save the file as a bmp which basically works by using wxpython's icon to bitmap workings and saves the image as well. However, I would the code to simply not use wxpython since I'm using Tkinter to code the interface itself .
Here's the code that currently works (adapted slightly) from http://ginstrom.com/scribbles/2007/08/31/file-list-with-icons-on-wxpython-windows/
import wx
from win32com.shell import shell, shellcon
from win32con import FILE_ATTRIBUTE_NORMAL
def extension_to_bitmap(extension):
"""dot is mandatory in extension"""
flags = shellcon.SHGFI_SMALLICON | \
shellcon.SHGFI_ICON | \
shellcon.SHGFI_USEFILEATTRIBUTES
retval, info = shell.SHGetFileInfo(extension,
FILE_ATTRIBUTE_NORMAL,
flags)
# non-zero on success
assert retval
hicon, iicon, attr, display_name, type_name = info
# Get the bitmap
icon = wx.EmptyIcon()
icon.SetHandle(hicon)
return wx.BitmapFromIcon(icon)
root = wx.App()
bitmapFile = extension_to_bitmap(".png")
bitmapFile.SaveFile('test.bmp', wx.BITMAP_TYPE_BMP)
Any help is greatly appreciated!
Inspired by IronManMark20's answer. This version returns a PIL image so it doesn't require the disc I/O of creating a temporary file. It also can get the different image sizes (see below) For more information, check this blog post.
from win32com.shell import shell, shellcon
from PIL import Image, ImageTk
import win32api
import win32con
import win32ui
import win32gui
def get_icon(PATH, size):
SHGFI_ICON = 0x000000100
SHGFI_ICONLOCATION = 0x000001000
if size == "small":
SHIL_SIZE = 0x00001
elif size == "large":
SHIL_SIZE = 0x00002
else:
raise TypeError("Invalid argument for 'size'. Must be equal to 'small' or 'large'")
ret, info = shell.SHGetFileInfo(PATH, 0, SHGFI_ICONLOCATION | SHGFI_ICON | SHIL_SIZE)
hIcon, iIcon, dwAttr, name, typeName = info
ico_x = win32api.GetSystemMetrics(win32con.SM_CXICON)
hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
hbmp = win32ui.CreateBitmap()
hbmp.CreateCompatibleBitmap(hdc, ico_x, ico_x)
hdc = hdc.CreateCompatibleDC()
hdc.SelectObject(hbmp)
hdc.DrawIcon((0, 0), hIcon)
win32gui.DestroyIcon(hIcon)
bmpinfo = hbmp.GetInfo()
bmpstr = hbmp.GetBitmapBits(True)
img = Image.frombuffer(
"RGBA",
(bmpinfo["bmWidth"], bmpinfo["bmHeight"]),
bmpstr, "raw", "BGRA", 0, 1
)
if size == "small":
img = img.resize((16, 16), Image.ANTIALIAS)
return img
Oddly enough, Python doesn't seem to have much for creating / editing *.ico files. It sounds like your best bet is to get the Python bindings for ImageMagick:
https://stackoverflow.com/questions/45507/is-there-a-python-library-for-generating-ico-files
I couldn't find any documentation specific to the bindings though. From what I have read, the Python Imaging Library (PIL) can read icon files, but not create them. However, you can probably use PIL to create bitmap files:
http://effbot.org/imagingbook/
http://vkedco.blogspot.com/2011/02/creating-and-saving-bitmaps-with-python.html
I recently had to do a similar task, and I used the following (requires pywin32 and PIL or Pillow). Basically, you get the handle of the icon, and make a copy. This returns a PIL image. You can open the Icontemp.bmp using something else, if you want.
def icon32(PATH):
SHGFI_ICON = 0x000000100
SHGFI_ICONLOCATION = 0x000001000
SHIL_EXTRALARGE = 0x00002
ret, info = shell.SHGetFileInfo(PATH, 0, SHGFI_ICONLOCATION | SHGFI_ICON | SHIL_EXTRALARGE)
hIcon, iIcon, dwAttr, name, typeName = info
tempDirectory = os.getenv("temp")
ico_x = win32api.GetSystemMetrics(win32con.SM_CXICON)
#creating a destination memory DC
hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
hbmp = win32ui.CreateBitmap()
hbmp.CreateCompatibleBitmap(hdc, ico_x, ico_x)
hdc = hdc.CreateCompatibleDC()
hdc.SelectObject(hbmp)
hdc.DrawIcon((0, 0), hIcon)
win32gui.DestroyIcon(hIcon)
hbmp.SaveBitmapFile(hdc, tempDirectory + "\Icontemp.bmp")
icon = QIcon(tempDirectory + "\Icontemp.bmp")
os.remove(tempDirectory + "\Icontemp.bmp")
return icon

Categories

Resources