Source code for imagecat.units

# Copyright 2020 Timothy M. Shead
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


"""Functionality for performing unit conversions.
"""

import numbers
import re


[docs]def length(value, size, default="px"): """Convert a length value to pixels. Supported unit abbreviations include: :"px", "pixel", "pixels": absolute length in pixels :"w", "width": relative length, as a fraction of the width of an image :"h", "height": relative length, as a fraction of the height of an image :"min": relative length, as a fraction of the smaller of width and height :"max": relative length, as a fraction of the larger of width and height Relative lengths will be relative to some reference that is context-specific and documented. For example: the text operator fontsize is relative to the size of the output image. Parameters ---------- value: number, :any:`str` or (number, :any:`str`) tuple, required Value to be converted. The value may be a number (in which case the `default` parameter will specify the unit of measure), a :any:`str` containing a number and unit abbreviation, or a (value, units) tuple. size: (width, height) tuple, required Reference width and height for use when the caller specifies a relative unit of measure. Note that width and height *must* be specified in pixels. default: :any:`str`, optional Default unit of measure to use when `value` is a plain number. Returns ------- value: number `value` converted to pixel units. Note that the result is a floating-point number, so callers may need to convert to an int if they are intend to e.g. specifying the resolution of an image. """ if isinstance(value, numbers.Number): value = (value, default) elif isinstance(value, str): value, units = re.match(r"([^a-zA-Z%]+)([a-zA-Z%]+)\Z", value).groups() value = (float(value), units) if not isinstance(value, tuple): raise ValueError("Value must be a number, string or (number, string) tuple.") # pragma: no cover if not len(value) == 2: raise ValueError("Value must be a number, string or (number, string) tuple.") # pragma: no cover if not isinstance(value[0], numbers.Number): raise ValueError("Value must be a number, string or (number, string) tuple.") # pragma: no cover if not isinstance(value[1], str): raise ValueError("Value must be a number, string or (number, string) tuple.") # pragma: no cover value, units = value units = units.lower() if units in {"px", "pixel", "pixels"}: return value if units in {"w", "width"}: return value * size[0] if units in {"h", "height"}: return value * size[1] if units in {"min"}: return value * min(size[0], size[1]) if units in {"max"}: return value * max(size[0], size[1]) raise ValueError("Unknown unit of measure: %s" % units) # pragma: no cover