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)
Related
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
I'm running a simple PDF to image conversion using Python PDF2Image library. I can certainly understand that the max memory threshold is being crossed by this library to arrive at this error. But, the PDF is 6.6 MB (approx), then why would it take up GBs of memory to throw a memory error?
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:06:47) [MSC v.1914 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from pdf2image import convert_from_path
>>> pages = convert_from_path(r'C:\Users\aakashba598\Documents\pwc-annual-report-2017-2018.pdf', 200)
Exception in thread Thread-3:
Traceback (most recent call last):
File "C:\Users\aakashba598\AppData\Local\Programs\Python\Python37-32\lib\threading.py", line 917, in _bootstrap_inner
self.run()
File "C:\Users\aakashba598\AppData\Local\Programs\Python\Python37-32\lib\threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\aakashba598\AppData\Local\Programs\Python\Python37-32\lib\subprocess.py", line 1215, in _readerthread
buffer.append(fh.read())
MemoryError
Also, what is the possible solution to this?
Update: When I reduced the dpi parameter from the convert_from_path function, it works like a charm. But the pictures produced are low quality (for obvious reasons). Is there a way to fix this? Like batch by batch creation of images and clearing memory everytime. If there is a way, how to go about it?
Convert the PDF in blocks of 10 pages each time ( 1-10,11-20 and so on ... )
from pdf2image import pdfinfo_from_path,convert_from_path
info = pdfinfo_from_path(pdf_file, userpw=None, poppler_path=None)
maxPages = info["Pages"]
for page in range(1, maxPages+1, 10) :
convert_from_path(pdf_file, dpi=200, first_page=page, last_page = min(page+10-1,maxPages))
I am a bit late to this, but the problem is indeed related to the 136 pages going into memory. You can do three things.
Specify a format for the converted images.
By default, pdf2image uses PPM as its image format, it is faster, but also takes a lot more memory (over 30MB per image!). What you can do to fix this is use a more memory-friendly format like jpeg or png.
convert_from_path('C:\path\to\your\pdf', fmt='jpeg')
That will probably solve the problem, but it's mostly just because of the compression, and at some point (say for +500pages PDF) the problem will reappear.
Use an output directory
This is the one I would recommend because it allows you to process any PDF. The example on the README page explains it well:
import tempfile
with tempfile.TemporaryDirectory() as path:
images_from_path = convert_from_path('C:\path\to\your\pdf', output_folder=path)
This writes the image to your computer storage temporarily so you don't have to delete it manually. Make sure to do any processing you need to do before exiting the with context though!
Process the PDF file in chunks
pdf2image allows you to define the first an last page that you want to process. That means that in your case, with a PDF of 136 pages, you could do:
for i in range(0, 136 // 10 + 1):
convert_from_path('C:\path\to\your\pdf', first_page=i*10, last_page=(i+1)*10)
The accepted answer has a small issue.
maxPages = pdf2image._page_count(pdf_file)
can no longer be used, as _page_count is deprecated. I found the working solution for the same.
from PyPDF2 import PdfFileWriter, PdfFileReader
inputpdf = PdfFileReader(open(pdf, "rb"))
maxPages = inputpdf.numPages
for page in range(1, maxPages, 100):
pil_images = pdf2image.convert_from_path(pdf, dpi=200, first_page=page,
last_page=min(page + 100 - 1, maxPages), fmt= 'jpg',
thread_count=1, userpw=None,
use_cropbox=False, strict=False)
This way, however large the file, it will process 100 at once and the ram usage is always minimal.
A relatively big PDF will use up all your memory and cause the process to be killed (unless you use an output folder)
https://github.com/Belval/pdf2image i guess will help you to understand.
Solution: Break the pdf in small parts and convert it into image. The image could be merge...
from PyPDF2 import PdfFileWriter, PdfFileReader
inputpdf = PdfFileReader(open("document.pdf", "rb"))
for i in range(inputpdf.numPages):
output = PdfFileWriter()
output.addPage(inputpdf.getPage(i))
with open("document-page%s.pdf" % i, "wb") as outputStream:
output.write(outputStream)
split a multi-page pdf file into multiple pdf files with python?
import numpy as np
import PIL
list_im = ['Test1.jpg', 'Test2.jpg', 'Test3.jpg']
imgs = [ PIL.Image.open(i) for i in list_im ]
# pick the image which is the smallest, and resize the others to match it (can be arbitrary image shape here)
min_shape = sorted( [(np.sum(i.size), i.size ) for i in imgs])[0][1]
imgs_comb = np.hstack( (np.asarray( i.resize(min_shape) ) for i in imgs ) )
# save that beautiful picture
imgs_comb = PIL.Image.fromarray( imgs_comb)
imgs_comb.save( 'Trifecta.jpg' )
# for a vertical stacking it is simple: use vstack
imgs_comb = np.vstack( (np.asarray( i.resize(min_shape) ) for i in imgs ) )
imgs_comb = PIL.Image.fromarray( imgs_comb)
imgs_comb.save( 'Trifecta_vertical.jpg' )
refer:Combine several images horizontally with Python
eventually, combining these techniques, I ended up coding like following, given the goal to convert a pdf into a pptx with avoiding memory overflow and good speed in mind:
import os, sys, tempfile, pprint
from PIL import Image
from pdf2image import pdfinfo_from_path,convert_from_path
from pptx import Presentation
from pptx.util import Inches
from io import BytesIO
pdf_file = sys.argv[1]
print("Converting file: " + pdf_file)
# Prep presentation
prs = Presentation()
blank_slide_layout = prs.slide_layouts[6]
# Create working folder
base_name = pdf_file.split(".pdf")[0]
# Convert PDF to list of images
print("Starting conversion...")
print()
path: str = "C:/ppttemp" #temp dir (use cron to delete files older than 1h hourly)
slideimgs = []
info = pdfinfo_from_path(pdf_file, userpw=None, poppler_path='C:/Program Files/poppler-0.90.1/bin/')
maxPages = info["Pages"]
for page in range(1, maxPages+1, 5) :
slideimgs.extend( convert_from_path(pdf_file, dpi=250, output_folder=path, first_page=page, last_page = min(page+5-1,maxPages), fmt='jpeg', thread_count=4, poppler_path='C:/Program Files/poppler-0.90.1/bin/', use_pdftocairo=True) )
print("...complete.")
print()
# Loop over slides
for i, slideimg in enumerate(slideimgs):
if i % 5 == 0:
print("Saving slide: " + str(i))
imagefile = BytesIO()
slideimg.save(imagefile, format='jpeg')
imagedata = imagefile.getvalue()
imagefile.seek(0)
width, height = slideimg.size
# Set slide dimensions
prs.slide_height = height * 9525
prs.slide_width = width * 9525
# Add slide
slide = prs.slides.add_slide(blank_slide_layout)
pic = slide.shapes.add_picture(imagefile, 0, 0, width=width * 9525, height=height * 9525)
# Save Powerpoint
print("Saving file: " + base_name + ".pptx")
prs.save(base_name + '.pptx')
print("Conversion complete. :)")
print()
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 )
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()
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