from __future__ import annotations
import ctypes as ct
import tempfile
import os
import warnings
import sys
from .utils import convert_dib_to_bmp
def _win_check(result, func, _):
if func is GlobalFree:
if result:
raise ct.WinError()
return None
if func is GlobalUnlock:
if not result and ct.GetLastError() != 0:
raise ct.WinError()
return result
if func is GetMessage:
if result == -1:
raise ct.WinError()
return result
if func is TranslateMessage or func is DispatchMessage:
return result
if not result:
raise ct.WinError()
return result
if sys.platform == "win32":
GlobalLock = ct.windll.kernel32.GlobalLock
GlobalLock.argtypes = [ct.c_void_p]
GlobalLock.restype = ct.c_void_p
GlobalLock.errcheck = _win_check
GlobalUnlock = ct.windll.kernel32.GlobalUnlock
GlobalUnlock.argtypes = [ct.c_void_p]
GlobalUnlock.errcheck = _win_check
GlobalAlloc = ct.windll.kernel32.GlobalAlloc
GlobalAlloc.restype = ct.c_void_p
GlobalAlloc.errcheck = _win_check
GlobalFree = ct.windll.kernel32.GlobalFree
GlobalFree.argtypes = [ct.c_void_p]
GlobalFree.errcheck = _win_check
GlobalSize = ct.windll.kernel32.GlobalSize
GlobalSize.argtypes = [ct.c_void_p]
GlobalSize.restype = ct.c_size_t
GlobalSize.errcheck = _win_check
GetMessage = ct.windll.user32.GetMessageW
TranslateMessage = ct.windll.user32.TranslateMessage
TranslateMessage.errcheck = _win_check
DispatchMessage = ct.windll.user32.DispatchMessageW
DispatchMessage.errcheck = _win_check
GMEM_ZEROINIT = 0x0040
[docs]
def dib_to_bm_file(handle, path: str | None = None) -> bytes | None:
"""Convert a DIB (Device Independent Bitmap) to a windows
bitmap file format. The BitMap file is either returned as
a string, or written to a file with the name given in the
second argument.
.. note::
Can only be used with lowlevel 1.x sources
"""
size = GlobalSize(handle)
ptr = GlobalLock(handle)
try:
dib_bytes = (ct.c_char * size).from_address(ptr)
bmp = convert_dib_to_bmp(dib_bytes)
if path:
with open(path, "wb") as f:
f.write(bmp)
else:
return bmp
finally:
GlobalUnlock(handle)
return None
[docs]
def dib_to_xbm_file(handle, path: str | None = None):
"""Convert a DIB (Device Independent Bitmap) to an X-Windows
bitmap file (XBM format). The XBM file is either returned as
a string, or written to a file with the name given in the
third argument.
Parameters:
:param handle: Handle to a global area containing a DIB,
:param path: Path prefix to be used for the name and an optional filename
for file only output.
.. note::
Can only be used with lowlevel 1.x sources
"""
handle, bmppath = tempfile.mkstemp(".bmp")
os.close(handle)
dib_to_bm_file(handle, bmppath)
try:
# Needs fixing
import Image # type: ignore
except ImportError:
from PIL import Image
Image.open(bmppath).save(path, "xbm")
os.remove(bmppath)
[docs]
def global_handle_get_bytes(handle, offset: int, count: int) -> bytes:
"""Read a specified number of bytes from a global handle.
Parameters:
:param handle: Global handle
:param offset: An index into the handle data
:param count: The number of bytes to be returned
.. note::
Can only be used with lowlevel 1.x sources
"""
size = GlobalSize(handle)
ptr = GlobalLock(handle)
try:
char_ptr = ct.cast(ptr, ct.POINTER(ct.c_char))
return char_ptr[min(offset, size) : min(offset + count, size)] # type: ignore # needs fixing
finally:
GlobalUnlock(handle)
[docs]
def global_handle_put_bytes(handle, offset: int, count: int, data: bytes):
"""Write a specified number of bytes to a global handle.
Parameters:
:param handle: Global handle
:param offset: An index into the handle data
:param count: The number of bytes to update
:param data: String of data to be written
.. note::
Can only be used with lowlevel 1.x sources
"""
size = GlobalSize(handle)
ptr = GlobalLock(handle)
try:
char_ptr = ct.cast(ptr, ct.POINTER(ct.c_char))
offset = min(offset, size)
end = min(offset + count, size)
count = end - offset
count = min(count, len(data))
for i in range(count):
char_ptr[i + offset] = data[i]
finally:
GlobalUnlock(handle)
[docs]
def global_handle_allocate(flags: int, size: int):
"""Allocate a specified number of bytes via a global handle.
Parameters:
:param size: The number of bytes to be allocated
.. note::
Can only be used with lowlevel 1.x sources
"""
return GlobalAlloc(flags, size)
[docs]
def global_handle_free(handle):
"""Free an allocated heap section via the global handle.
Parameters:
:param handle: Handle to memory to be freed
.. note::
Can only be used with lowlevel 1.x sources
"""
return GlobalFree(handle)
# backward compatible aliases
[docs]
def DIBToBMFile(handle, path=None):
"""Backward compatible alias for :func:`dib_to_bm_file`"""
warnings.warn(
"DIBToBMFile is deprecated, use dib_to_bm_file instead", DeprecationWarning
)
return dib_to_bm_file(handle, path)
[docs]
def DIBToXBMFile(handle, path=None):
"""Backward compatible alias for :func:`dib_to_xbm_file`"""
warnings.warn(
"DIBToXBMFile is deprecated, use dib_to_xbm_file instead", DeprecationWarning
)
return dib_to_xbm_file(handle, path)
[docs]
def GlobalHandleGetBytes(handle, offset, count):
"""Backward compatible alias for :func:`global_handle_get_bytes`"""
warnings.warn(
"GlobalHandleGetBytes is deprecated, use global_handle_get_bytes instead",
DeprecationWarning,
)
return global_handle_get_bytes(handle, offset, count)
[docs]
def GlobalHandlePutBytes(handle, offset, count, data):
"""Backward compatible alias for :func:`global_handle_put_bytes`"""
warnings.warn(
"GlobalHandlePutBytes is deprecated, use global_handle_put_bytes instead",
DeprecationWarning,
)
return global_handle_put_bytes(handle, offset, count, data)
[docs]
def GlobalHandleAllocate(flags, size):
"""Backward compatible alias for :func:`global_handle_allocate`"""
warnings.warn(
"GlobalHandleAllocate is deprecated, use global_handle_allocate instead",
DeprecationWarning,
)
return global_handle_allocate(flags, size)
[docs]
def GlobalHandleFree(handle):
"""Backward compatible alias for :func:`global_handle_free`"""
warnings.warn(
"GlobalHandleFree is deprecated, use global_handle_free instead",
DeprecationWarning,
)
return global_handle_free(handle)