Preserve bytes immutability.

`nanosvg` modifies its input strings in place (see: 9dd92bbfc6/src/nanosvg.h (L348)),
which will lead to issues attempting to use the same python `bytes` object multiple times. Since bytes objects promise immutability its undesirable to permit them to be modified like this.
To correct for this, we'll copy the bytes object into a new location in memory and pass that new memory location to nanosvg.
This commit is contained in:
Mesalu
2020-06-15 13:34:05 -07:00
committed by GitHub
parent bda5fbefd7
commit ecb78f75b1

View File

@@ -150,16 +150,33 @@ cdef class SVGimageBase:
@classmethod
def CreateFromBytes(cls, bytes buffer, str units='px', float dpi=96):
def CreateFromBytes(cls, bytes buffer, str units='px', float dpi=96, bool do_copy=True):
"""
Loads an SVG image from a bytes object.
:param bytes `buffer`: object containing the SVG data
:param str `units`: One of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'
:param float `dpi`: controls how the unit conversion is done
:param bool `do_copy`: indicates if the given bytes object should be
copied to avoid in-place modification. This should be set to True
if the given `buffer` object may ever be reused in any capacity.
If the given `buffer` will only be used once, and the cost of copying
it is problematic, then `do_copy` can be set to False.
:rtype: An instance of ``cls`` (usually a :class:`SVGimage`)
"""
if do_copy:
# `nsvgParse` will end up modifying the char-array passed to it in-place
# which will violate the immutability of python `bytes` objects.
# To avoid this we're going to copy the given `buffer` object into
# an entirely separate portion of memory. Unfortunately, python is a
# step ahead of the game and optimizes copying byte strings into just
# returning the same object (because they're immutable!), so to truly
# get a different byte string we'll copy it via converting to a bytearray
# and back:
buffer = bytes(bytearray(buffer))
units_b = units.encode('utf-8')
cdef SVGimageBase img = cls()
img._set_ptr(nsvgParse(buffer, units_b, dpi),