Skip to content

Improve support for GFlags types #429

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 1, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 30 additions & 16 deletions examples/gen-enums.py
Original file line number Diff line number Diff line change
@@ -3,11 +3,11 @@
import sys
import xml.etree.ElementTree as ET

from pyvips import ffi, values_for_enum, vips_lib, \
type_map, type_name, type_from_name
from pyvips import ffi, values_for_enum, values_for_flag, \
vips_lib, type_map, type_name, type_from_name

# This file generates enums.py -- the set of classes giving the permissible
# values for the pyvips enums. Run with something like:
# values for the pyvips enums/flags. Run with something like:
#
# ./gen-enums.py ~/GIT/libvips/libvips/Vips-8.0.gir > enums.py
# mv enums.py ../pyvips
@@ -18,11 +18,15 @@
"goi": "http://www.gtk.org/introspection/core/1.0"
}

# find all the enumerations and make a dict for them
# find all the enumerations/flags and make a dict for them
xml_enums = {}
for node in root.findall("goi:namespace/goi:enumeration", namespace):
xml_enums[node.get('name')] = node

xml_flags = {}
for node in root.findall("goi:namespace/goi:bitfield", namespace):
xml_flags[node.get('name')] = node


def remove_prefix(enum_str):
prefix = 'Vips'
@@ -33,31 +37,41 @@ def remove_prefix(enum_str):
return enum_str


def generate_enums():
def generate_enums_flags():
# otherwise we're missing some enums
vips_lib.vips_token_get_type()
vips_lib.vips_saveable_get_type()
vips_lib.vips_image_type_get_type()

all_enums = []
all_nicknames = []

def add_enum(gtype, a, b):
def add_nickname(gtype, a, b):
nickname = type_name(gtype)
all_enums.append(nickname)
all_nicknames.append(nickname)

type_map(gtype, add_enum)
type_map(gtype, add_nickname)

return ffi.NULL

type_map(type_from_name('GEnum'), add_enum)
type_map(type_from_name('GEnum'), add_nickname)
type_map(type_from_name('GFlags'), add_nickname)

# Filter internal flags
filter = ['VipsForeignFlags']
all_nicknames = [name for name in all_nicknames if name not in filter]

for name in all_enums:
for name in all_nicknames:
gtype = type_from_name(name)
python_name = remove_prefix(name)
if python_name not in xml_enums:
if python_name in xml_enums:
node = xml_enums[python_name]
values = values_for_enum(gtype)
elif python_name in xml_flags:
node = xml_flags[python_name]
values = values_for_flag(gtype)
else:
continue

node = xml_enums[python_name]
enum_doc = node.find("goi:doc", namespace)

print('')
@@ -70,7 +84,7 @@ def add_enum(gtype, a, b):
print('')
print('Attributes:')
print('')
for value in values_for_enum(gtype):
for value in values:
python_name = value.replace('-', '_')
member = node.find(f"goi:member[@name='{python_name}']", namespace)
member_doc = member.find("goi:doc", namespace)
@@ -81,12 +95,12 @@ def add_enum(gtype, a, b):
print(' """')
print('')

for value in values_for_enum(gtype):
for value in values:
python_name = value.replace('-', '_').upper()
print(f' {python_name} = \'{value}\'')


if __name__ == "__main__":
print('# libvips enums -- this file is generated automatically')
print('# flake8: noqa: E501') # ignore line too long error
generate_enums()
generate_enums_flags()
148 changes: 118 additions & 30 deletions pyvips/enums.py
Original file line number Diff line number Diff line change
@@ -250,30 +250,28 @@ class Interpretation(object):
class DemandStyle(object):
"""DemandStyle.
See vips_image_pipelinev(). Operations can hint to the VIPS image IO
system about the kind of demand geometry they prefer.
See vips_image_pipelinev(). Operations can hint
the kind of demand geometry they prefer
to the VIPS image IO system.
These demand styles are given below in order of increasing
restrictiveness. When demanding output from a pipeline,
specialisation. When demanding output from a pipeline,
vips_image_generate()
will use the most restrictive of the styles requested by the operations
will use the most general style requested by the operations
in the pipeline.
#VIPS_DEMAND_STYLE_THINSTRIP --- This operation would like to output strips
the width of the image and a few pels high. This is option suitable for
point-to-point operations, such as those in the arithmetic package.
This option is only efficient for cases where each output pel depends
upon the pel in the corresponding position in the input image.
#VIPS_DEMAND_STYLE_SMALLTILE --- This is the most general demand format.
Output is demanded in small (around 100x100 pel) sections. This style works
reasonably efficiently, even for bizzarre operations like 45 degree rotate.
#VIPS_DEMAND_STYLE_FATSTRIP --- This operation would like to output strips
the width of the image and as high as possible. This option is suitable
for area operations which do not violently transform coordinates, such
as vips_conv().
#VIPS_DEMAND_STYLE_SMALLTILE --- This is the most general demand format.
Output is demanded in small (around 100x100 pel) sections. This style works
reasonably efficiently, even for bizzare operations like 45 degree rotate.
#VIPS_DEMAND_STYLE_THINSTRIP --- This operation would like to output strips
the width of the image and a few pels high. This option is suitable for
point-to-point operations, such as those in the arithmetic package.
#VIPS_DEMAND_STYLE_ANY --- This image is not being demand-read from a disc
file (even indirectly) so any demand style is OK. It's used for things like
@@ -283,9 +281,9 @@ class DemandStyle(object):
Attributes:
SMALLTILE (str): demand in small (typically 64x64 pixel) tiles
SMALLTILE (str): demand in small (typically 128x128 pixel) tiles
FATSTRIP (str): demand in fat (typically 10 pixel high) strips
FATSTRIP (str): demand in fat (typically 16 pixel high) strips
THINSTRIP (str): demand in thin (typically 1 pixel high) strips
@@ -359,11 +357,11 @@ class OperationMath2(object):
Attributes:
POW (str): pow( left, right )
POW (str): pow(left, right)
WOP (str): pow( right, left )
WOP (str): pow(right, left)
ATAN2 (str): atan2( left, right )
ATAN2 (str): atan2(left, right)
"""

@@ -405,6 +403,14 @@ class OperationMath(object):
ATAN (str): atan(), angles in degrees
LOG (str): log base e
LOG10 (str): log base 10
EXP (str): e to the something
EXP10 (str): 10 to the something
SINH (str): sinh(), angles in radians
COSH (str): cosh(), angles in radians
@@ -417,14 +423,6 @@ class OperationMath(object):
ATANH (str): atanh(), angles in radians
LOG (str): log base e
LOG10 (str): log base 10
EXP (str): e to the something
EXP10 (str): 10 to the something
"""

SIN = 'sin'
@@ -433,16 +431,16 @@ class OperationMath(object):
ASIN = 'asin'
ACOS = 'acos'
ATAN = 'atan'
LOG = 'log'
LOG10 = 'log10'
EXP = 'exp'
EXP10 = 'exp10'
SINH = 'sinh'
COSH = 'cosh'
TANH = 'tanh'
ASINH = 'asinh'
ACOSH = 'acosh'
ATANH = 'atanh'
LOG = 'log'
LOG10 = 'log10'
EXP = 'exp'
EXP10 = 'exp10'


class OperationRound(object):
@@ -808,6 +806,32 @@ class Precision(object):
APPROXIMATE = 'approximate'


class TextWrap(object):
"""TextWrap.
Sets the word wrapping style for vips_text() when used with a maximum
width.
See also: vips_text().
Attributes:
WORD (str): wrap at word boundaries
CHAR (str): wrap at character boundaries
WORD_CHAR (str): wrap at word boundaries, but fall back to character boundaries if there is not enough space for a full word
NONE (str): no wrapping
"""

WORD = 'word'
CHAR = 'char'
WORD_CHAR = 'word-char'
NONE = 'none'


class FailOn(object):
"""FailOn.
@@ -848,6 +872,9 @@ class ForeignPpmFormat(object):
#VIPS_FOREIGN_PPM_FORMAT_PFM images are 32-bit float pixels.
#VIPS_FOREIGN_PPM_FORMAT_PNM images are anymap images -- the image format
is used to pick the saver.
Attributes:
PBM (str): portable bitmap
@@ -858,12 +885,15 @@ class ForeignPpmFormat(object):
PFM (str): portable float map
PNM (str): portable anymap
"""

PBM = 'pbm'
PGM = 'pgm'
PPM = 'ppm'
PFM = 'pfm'
PNM = 'pnm'


class ForeignSubsample(object):
@@ -1119,6 +1149,34 @@ class ForeignHeifCompression(object):
AV1 = 'av1'


class ForeignHeifEncoder(object):
"""ForeignHeifEncoder.
The selected encoder to use.
If libheif hasn't been compiled with the selected encoder,
we will fallback to the default encoder for the compression format.
Attributes:
AUTO (str): auto
AOM (str): aom
RAV1E (str): RAV1E
SVT (str): SVT-AV1
X265 (str): x265
"""

AUTO = 'auto'
AOM = 'aom'
RAV1E = 'rav1e'
SVT = 'svt'
X265 = 'x265'


class Size(object):
"""Size.
@@ -1316,3 +1374,33 @@ class ImageType(object):
MMAPIN = 'mmapin'
MMAPINRW = 'mmapinrw'
OPENOUT = 'openout'


class ForeignPngFilter(object):
"""ForeignPngFilter.
http://www.w3.org/TR/PNG-Filters.html
The values mirror those of png.h in libpng.
Attributes:
NONE (str): no filtering
SUB (str): difference to the left
UP (str): difference up
AVG (str): average of left and up
PAETH (str): pick best neighbor predictor automatically
ALL (str): adaptive
"""

NONE = 'none'
SUB = 'sub'
UP = 'up'
AVG = 'avg'
PAETH = 'paeth'
ALL = 'all'
20 changes: 19 additions & 1 deletion pyvips/gvalue.py
Original file line number Diff line number Diff line change
@@ -126,6 +126,23 @@ def from_enum(gtype, enum_value):

return _to_string(pointer)

@staticmethod
def to_flag(gtype, value):
"""Turn a string into a flag value ready to be passed into libvips.
"""

if isinstance(value, basestring if _is_PY2 else str): # noqa: F821
flag_value = vips_lib.vips_flags_from_nick(b'pyvips', gtype,
_to_bytes(value))
if flag_value < 0:
raise Error('no value {0} in gtype {1} ({2})'.
format(value, type_name(gtype), gtype))
else:
flag_value = value

return flag_value

def __init__(self):
# allocate memory for the gvalue which will be freed on GC
self.pointer = ffi.new('GValue *')
@@ -173,7 +190,8 @@ def set(self, value):
gobject_lib.g_value_set_enum(self.gvalue,
GValue.to_enum(gtype, value))
elif fundamental == GValue.gflags_type:
gobject_lib.g_value_set_flags(self.gvalue, value)
gobject_lib.g_value_set_flags(self.gvalue,
GValue.to_flag(gtype, value))
elif gtype == GValue.gstr_type:
gobject_lib.g_value_set_string(self.gvalue, _to_bytes(value))
elif gtype == GValue.refstr_type:
2 changes: 2 additions & 0 deletions pyvips/vdecls.py
Original file line number Diff line number Diff line change
@@ -92,6 +92,8 @@ def cdefs(features):
int vips_enum_from_nick (const char* domain,
GType gtype, const char* str);
int vips_flags_from_nick (const char* domain,
GType gtype, const char* nick);
const char *vips_enum_nick (GType gtype, int value);
void g_value_set_boolean (GValue* value, int v_boolean);
4 changes: 2 additions & 2 deletions pyvips/vimage.py
Original file line number Diff line number Diff line change
@@ -1430,8 +1430,8 @@ def __getitem__(self, arg):

# n.b. We don't use isinstance because isinstance(True, int)
# is True!
if not (all(type(x) == int for x in arg) or
all(type(x) == bool for x in arg)):
if not (all(type(x) == int for x in arg) or # noqa: E721
all(type(x) == bool for x in arg)): # noqa: E721
raise IndexError('list must contain only ints or only bools')

if isinstance(arg[0], bool):