Главная » 2026 » Январь » 05 » UImage C API
18:26
UImage C API

UImage C API

Графическая библиотека UImageC содержит код на языке C, который можно вызвать из программ на Python, C или C++. Код компилируется в динамические библиотеки (dll) под Windows x64. Подключить библиотеку в программе на Python позволяет модуль ctypes, входящий в состав стандартной библиотеки. Пример подключения библиотеки libuimagegray.dll, расположенной в папке bin, относительно местоположения исполняемого файла:

import os.path
import ctypes

_ulibpath = os.path.abspath(
    os.path.join(os.path.dirname(__file__), "bin", "libuimagegray.dll"))
_ulibc = ctypes.CDLL(_ulibpath)

Следует учитывать, что при неправильном использовании функций из C API возможны непредвиденные последствия. Это касается всего языка C в целом. Например, функция принимает указатель на массив. Внутри функции нет никакой возможности определить число элементов массива. Оператор sizeof() вернет лишь размер указателя, а не размер всего массива. Число элементов массива обычно передается дополнительным параметром, но нет никакой гарантии, что это число соответствует реальному размеру массива. Поэтому контроль за правильностью передаваемых в функцию данных лежит на плечах программиста.

Знакомство с массивами ctypes

Пиксели изображения в библиотеке UImageC хранятся в массивах ctypes, что позволяет получить к ним доступ из программы на языке C без необходимости выполнения преобразований. В отличие от списков языка Python массивы ctypes являются строго типизированными и имеют фиксированный размер.

Типы данных в модуле ctypes соответствуют типам из языка C. Перечислим основные типы, которые часто встречаются в библиотеке UImageC:

>>> import ctypes
>>> b = ctypes.c_bool(True) # _Bool
>>> ctypes.sizeof(b)
1
>>> n = ctypes.c_ubyte(5) # unsigned char
>>> ctypes.sizeof(n)
1
>>> n = ctypes.c_int(5) # int или long
>>> ctypes.sizeof(n)
4
>>> n = ctypes.c_long(5) # long
>>> ctypes.sizeof(n)
4
>>> n = ctypes.c_float(5.2) # float
>>> ctypes.sizeof(n)
4
>>> n = ctypes.c_double(5.2) # double
>>> ctypes.sizeof(n)
8
>>> type(n)
<class 'ctypes.c_double'>
>>> n.value
5.2

Создать указатель позволяет функция pointer():

>>> n = ctypes.c_int(5)
>>> pn = ctypes.pointer(n)
>>> pn.contents
c_long(5)
>>> pn[0] = 10
>>> n
c_long(10)

Существует также функция POINTER(), которая используется для объявления типизированных указателей. Например, для прототипа:

int uimagergb_invert(unsigned char* parr, int arr_len);

код описания параметров выглядит так:

_uimagergb_invert = _ulibc.uimagergb_invert
_uimagergb_invert.argtypes = [
   ctypes.POINTER(ctypes.c_ubyte), ctypes.c_int]
_uimagergb_invert.restype = ctypes.c_int

Объявление указателя на C-строку (заканчивается нулевым символом) выполняется с помощью типа c_char_p. Например, для прототипа:

int uimagegray_to_bwstr(int* parr_int, int arr_len_int,
                        char* s, int s_len);

код описания параметров выглядит так:

_uimagegray_to_bwstr = _ulibc.uimagegray_to_bwstr
_uimagegray_to_bwstr.argtypes = [
   ctypes.POINTER(ctypes.c_int), ctypes.c_int,
   ctypes.c_char_p, ctypes.c_int]
_uimagegray_to_bwstr.restype = ctypes.c_int

Строки в языке Python неизменяемые. Для создания изменяемого строкового буфера предназначена функция create_string_buffer():

>>> s = b'Hello'
>>> ps = ctypes.create_string_buffer(s)
>>> ps.raw
b'Hello\x00'
>>> ps.value
b'Hello'
>>> type(ps)
<class 'ctypes.c_char_Array_6'>
>>> ctypes.sizeof(ps)
6
>>> ps[0] = b'_'
>>> ps.value
b'_ello'
>>> ps = ctypes.create_string_buffer(3)
>>> ps.raw
b'\x00\x00\x00'

Для создания типизированного массива нужно умножить тип на число элементов, а затем вызвать конструктор:

>>> arr = (ctypes.c_int * 5)()
>>> arr[:]
[0, 0, 0, 0, 0]
>>> arr = (ctypes.c_int * 5)(0, 1, 2, 3, 4)
>>> arr[:]
[0, 1, 2, 3, 4]
>>> arr[0]
0
>>> arr[0] = 55
>>> arr[:]
[55, 1, 2, 3, 4]

Создать массив на основе списка можно так:

>>> arr = [0, 1, 2, 3, 4]
>>> type(arr)
<class 'list'>
>>> arr2 = (ctypes.c_int * len(arr))(*arr)
>>> arr2[:]
[0, 1, 2, 3, 4]
>>> type(arr2)
<class '__main__.c_long_Array_5'>

Массивы являются экземплярами класса ctypes.Array. Проверить тип и получить информацию о массиве позволяет следующий код:

>>> arr = (ctypes.c_int * 5)(0, 1, 2, 3, 4)
>>> isinstance(arr, ctypes.Array)
True
>>> arr._length_
5
>>> arr._type_
<class 'ctypes.c_long'>
>>> ctypes.sizeof(arr)
20

Для преобразования массива в список можно использовать операцию извлечения среза или функцию list():

>>> arr = (ctypes.c_int * 5)(0, 1, 2, 3, 4)
>>> arr2 = arr[:]
>>> type(arr2)
<class 'list'>
>>> arr3 = list(arr)
>>> type(arr3)
<class 'list'>

Класс UCArray: работа с массивами ctypes

Класс UCArray содержит методы для работы с массивами ctypes. Инструкция импорта:

from unicross_img.uhelper import UCArray

Создание массива ctypes

Создать массив ctypes с типом c_int (c_long) позволяет статический метод create_ctypes_array_int() из класса UCArray. Формат метода:

UCArray.create_ctypes_array_int(width, height, num_channels)

В первом параметре указывается ширина изображения от 1 до 8000. Второй параметр задает высоту изображения от 1 до 8000. Параметр num_channels определяет число каналов изображения (1, 3 или 4). Метод возвращает массив ctypes заполненный нулями. При ошибке генерируется исключение. Пример:

from unicross_img.uhelper import UCArray

arr = UCArray.create_ctypes_array_int(3, 2, 1)
print(arr._length_) # 6
print(arr._type_)   # <class 'ctypes.c_long'>
print(arr[:])
# [0, 0, 0,
#  0, 0, 0]
arr = UCArray.create_ctypes_array_int(3, 2, 3)
print(arr._length_) # 18
print(arr[:])
# [0, 0, 0,   0, 0, 0,   0, 0, 0,
#  0, 0, 0,   0, 0, 0,   0, 0, 0]
arr = UCArray.create_ctypes_array_int(3, 2, 4)
print(arr._length_) # 24
print(arr[:])
# [0, 0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0,
#  0, 0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0]

Создать массив ctypes с типом c_ubyte (соответствует типу unsigned char в языке C) позволяет статический метод create_ctypes_array_ubyte() из класса UCArray. Формат метода:

UCArray.create_ctypes_array_ubyte(width, height, num_channels)

В первом параметре указывается ширина изображения от 1 до 8000. Второй параметр задает высоту изображения от 1 до 8000. Параметр num_channels определяет число каналов изображения (1, 3 или 4). Метод возвращает массив ctypes заполненный нулями. При ошибке генерируется исключение. Пример:

from unicross_img.uhelper import UCArray

arr = UCArray.create_ctypes_array_ubyte(3, 2, 1)
print(arr._length_) # 6
print(arr._type_)   # <class 'ctypes.c_ubyte'>
print(arr[:])
# [0, 0, 0,
#  0, 0, 0]
arr = UCArray.create_ctypes_array_ubyte(3, 2, 3)
print(arr._length_) # 18
print(arr[:])
# [0, 0, 0,   0, 0, 0,   0, 0, 0,
#  0, 0, 0,   0, 0, 0,   0, 0, 0]
arr = UCArray.create_ctypes_array_ubyte(3, 2, 4)
print(arr._length_) # 24
print(arr[:])
# [0, 0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0,
#  0, 0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0]

Создать массив ctypes с типом c_double позволяет статический метод create_ctypes_array_double() из класса UCArray. Формат метода:

UCArray.create_ctypes_array_double(width, height, num_channels)

В первом параметре указывается ширина изображения от 1 до 8000. Второй параметр задает высоту изображения от 1 до 8000. Параметр num_channels определяет число каналов изображения (1, 3 или 4). Метод возвращает массив ctypes заполненный нулями. При ошибке генерируется исключение. Пример:

from unicross_img.uhelper import UCArray

arr = UCArray.create_ctypes_array_double(3, 2, 1)
print(arr._length_) # 6
print(arr._type_)   # <class 'ctypes.c_double'>
print(arr[:])
# [0.0, 0.0, 0.0,
#  0.0, 0.0, 0.0]
arr = UCArray.create_ctypes_array_double(3, 2, 3)
print(arr._length_) # 18
print(arr[:])
# [0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0,
#  0.0, 0.0, 0.0,   0.0, 0.0, 0.0,   0.0, 0.0, 0.0]
arr = UCArray.create_ctypes_array_double(3, 2, 4)
print(arr._length_) # 24
print(arr[:])
# [0.0, 0.0, 0.0, 0.0,   0.0, 0.0, 0.0, 0.0,   0.0, 0.0, 0.0, 0.0,
#  0.0, 0.0, 0.0, 0.0,   0.0, 0.0, 0.0, 0.0,   0.0, 0.0, 0.0, 0.0]

Создать массив ctypes с типом c_bool позволяет статический метод create_ctypes_array_bool() из класса UCArray. Формат метода:

UCArray.create_ctypes_array_bool(width, height)

В первом параметре указывается ширина изображения от 1 до 8000. Второй параметр задает высоту изображения от 1 до 8000. Метод возвращает массив ctypes заполненный значениями False. При ошибке генерируется исключение. Пример:

from unicross_img.uhelper import UCArray

arr = UCArray.create_ctypes_array_bool(3, 2)
print(arr._length_) # 6
print(arr._type_)   # <class 'ctypes.c_bool'>
print(arr[:])
# [False, False, False,
#  False, False, False]

Создание массива ctypes на основе списка

Создать массив ctypes с типом c_int (c_long) на основе списка с целыми числами позволяет статический метод create_ctypes_array_int_from_list() из класса UCArray. Формат метода:

UCArray.create_ctypes_array_int_from_list(<Список>)

Метод возвращает массив ctypes. При ошибке генерируется исключение. Пример:

from unicross_img.uhelper import UCArray

list_int = [0, 64, 128, 200, 255]
arr = UCArray.create_ctypes_array_int_from_list(list_int)
print(arr._length_) # 5
print(arr._type_)   # <class 'ctypes.c_long'>
print(arr[:])       # [0, 64, 128, 200, 255]

Создать массив ctypes с типом c_double на основе списка с вещественными числами позволяет статический метод create_ctypes_array_double_from_list() из класса UCArray. Формат метода:

UCArray.create_ctypes_array_double_from_list(<Список>)

Метод возвращает массив ctypes. При ошибке генерируется исключение. Пример:

from unicross_img.uhelper import UCArray

list_d = [0.0, 0.5, 1.0]
arr = UCArray.create_ctypes_array_double_from_list(list_d)
print(arr._length_) # 3
print(arr._type_)   # <class 'ctypes.c_double'>
print(arr[:])       # [0.0, 0.5, 1.0]

Создать массив ctypes с типом c_bool на основе списка с логическими значениями позволяет статический метод create_ctypes_array_bool_from_list() из класса UCArray. Формат метода:

UCArray.create_ctypes_array_bool_from_list(<Список>)

Метод возвращает массив ctypes. При ошибке генерируется исключение. Пример:

from unicross_img.uhelper import UCArray

list_b = [True, False, True]
arr = UCArray.create_ctypes_array_bool_from_list(list_b)
print(arr._length_) # 3
print(arr._type_)   # <class 'ctypes.c_bool'>
print(arr[:])       # [True, False, True]

Создание массива ctypes на основе объекта типа bytes

Создать массив ctypes с типом c_ubyte на основе объекта типа bytes или bytearray позволяет статический метод create_ctypes_array_ubyte_from_bytes() из класса UCArray. Формат метода:

UCArray.create_ctypes_array_ubyte_from_bytes(<bytes>)

Метод возвращает массив ctypes. При ошибке генерируется исключение. Пример:

from unicross_img.uhelper import UCArray

b = bytes([0, 1, 2, 3, 4])
print(type(b))      # <class 'bytes'>
arr = UCArray.create_ctypes_array_ubyte_from_bytes(b)
print(arr._length_) # 5
print(arr._type_)   # <class 'ctypes.c_ubyte'>
print(arr[:])       # [0, 1, 2, 3, 4]
b = bytearray(b)
print(type(b))      # <class 'bytearray'>
arr = UCArray.create_ctypes_array_ubyte_from_bytes(b)
print(arr._length_) # 5
print(arr._type_)   # <class 'ctypes.c_ubyte'>
print(arr[:])       # [0, 1, 2, 3, 4]

Создание копии массива ctypes

Создать копию массива ctypes с типом c_ubyte позволяет статический метод copy_ctypes_array_ubyte() из класса UCArray. Формат метода:

UCArray.copy_ctypes_array_ubyte(<Массив ctypes>)

Метод возвращает массив ctypes. При ошибке генерируется исключение. Пример:

import ctypes
from unicross_img.uhelper import UCArray

arr = (ctypes.c_ubyte * 5)(0, 1, 2, 3, 4)
arr2 = UCArray.copy_ctypes_array_ubyte(arr)
print(arr2._length_) # 5
print(arr2._type_)   # <class 'ctypes.c_ubyte'>
arr2[0] = 55
print(arr2[:])       # [55, 1, 2, 3, 4]
print(arr[:])        # [0, 1, 2, 3, 4]

Создать копию массива ctypes произвольного типа позволяет статический метод copy_ctypes_array() из класса UCArray. Формат метода:

UCArray.copy_ctypes_array(<Массив ctypes>)

Метод возвращает массив ctypes. При ошибке генерируется исключение. Пример:

import ctypes
from unicross_img.uhelper import UCArray

arr = (ctypes.c_int * 5)(0, 1, 2, 3, 4)
arr2 = UCArray.copy_ctypes_array(arr)
print(arr2._length_) # 5
print(arr2._type_)   # <class 'ctypes.c_long'>
arr2[0] = 55
print(arr2[:])       # [55, 1, 2, 3, 4]
print(arr[:])        # [0, 1, 2, 3, 4]

arr = (ctypes.c_double * 3)(0.0, 0.5, 1.0)
arr2 = UCArray.copy_ctypes_array(arr)
print(arr2._length_) # 3
print(arr2._type_)   # <class 'ctypes.c_double'>
arr2[0] = 1.0
print(arr2[:])       # [1.0, 0.5, 1.0]
print(arr[:])        # [0.0, 0.5, 1.0]

Класс входит в состав графической библиотеки UImageC. Описание библиотеки UImageC

Категория: UImage C | Просмотров: 7 | Добавил: unicross | Теги: UCArray, UImageC | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Категории раздела
Списки слов [10]
Списки слов и словари
OCR [4]
Оптическое распознавание символов
UImage [80]
Графическая библиотека для Python
UImage C [7]
Графическая библиотека для Python
Программы [4]
Полезные программы
Прочее [3]
Другие темы
Календарь
«  Январь 2026  »
Пн Вт Ср Чт Пт Сб Вс
   1234
567891011
12131415161718
19202122232425
262728293031