Skip to content

Commit

Permalink
allow Unicode filenames on utf-8 systems (e.g. not Windows)
Browse files Browse the repository at this point in the history
  • Loading branch information
Adios Automated Script committed Nov 18, 2021
1 parent 892d11d commit dd64edf
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 20 deletions.
66 changes: 46 additions & 20 deletions py_gd/py_gd.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ from py_gd cimport *
from libc.stdio cimport FILE, fopen, fclose
from libc.string cimport memcpy, strlen
from libc.stdlib cimport malloc, free
import os
# from libc.stdint cimport uint8_t, uint32_t

import os
import sys
import operator

import numpy as np
Expand Down Expand Up @@ -79,6 +80,32 @@ cpdef cnp.ndarray[int, ndim=2, mode='c'] asn2array(obj, dtype):
return arr


cdef bytes path_to_bytes(path):
"""
converts a "path like" object to bytes, suitable for passing to
the C fopen().
currently only supports ascii on non-utf-8 systems.
Itwould be good to figure how to do this on Windows
- UTF-16 and _wfopen(), I think
"""
# make it a string
cdef bytes bpath

path = os.fspath(path)
if sys.getfilesystemencoding() == 'utf-8':
bpath = path.encode('utf-8')
else:
try:
bpath = path.encode('ascii')
except UnicodeEncodeError:
raise ValueError("Can only accept ASCII filenames on this platform: "
f"{path}\n is not legal.")
return bpath


cdef class Image:
"""
class wrapper around a gdImage object
Expand Down Expand Up @@ -448,13 +475,14 @@ cdef class Image:
cdef FILE *fp
cdef int compression_level

file_name = os.fspath(file_name)
try:
file_path = file_name.encode('ascii')
except UnicodeEncodeError:
raise ValueError('can only accept ascii filenames')
file_path =path_to_bytes(file_name)
# file_name = os.fspath(file_name)
# try:
# file_path = file_name.encode('ascii')
# except UnicodeEncodeError:
# raise ValueError('can only accept ascii filenames')

file_type_codes = ["bmp", "jpg", "jpeg", "gif", "GIF", "png", "PNG"]
file_type_codes = {"bmp", "jpg", "jpeg", "gif", "GIF", "png", "PNG"}

if file_type not in file_type_codes:
raise ValueError('file_type must be one of: {}'
Expand Down Expand Up @@ -1062,11 +1090,13 @@ cdef class Animation:
all images in the animation. If 0,
a new colormap is used for each frame.
"""
file_name = os.fspath(file_name)
try:
self._file_path = file_name.encode('ascii')
except UnicodeEncodeError as err:
raise ValueError("can only accept ascii filenames") from err
self._file_path =path_to_bytes(file_name)

# file_name = os.fspath(file_name)
# try:
# self._file_path = file_name.encode('ascii')
# except UnicodeEncodeError as err:
# raise ValueError("can only accept ascii filenames") from err

self._fp = NULL
self.base_delay = delay
Expand Down Expand Up @@ -1230,18 +1260,14 @@ cdef class Animation:
NOTE: begin_anim needs to be called again
:param file_path: path and filename of new animation
:param file_path: str
:param file_path=None: filename of new animation. Will reuse existing
name if not specified
:param file_path: pathlike
"""
#fixme: should this use the existing file path by default?
self.prev_frame = None

if file_path is not None:
file_path = os.fspath(file_path)
try:
self._file_path = file_path.encode('ascii')
except UnicodeEncodeError:
raise ValueError('can only except ascii filenames')
self._file_path = path_to_bytes(file_path)

if self._fp is not NULL:
fclose(self._fp)
Expand Down
21 changes: 21 additions & 0 deletions py_gd/test/test_gd.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"""

import os
import sys
import hashlib
from pathlib import Path
import numpy as np
Expand Down Expand Up @@ -122,6 +123,26 @@ def test_cant_save_file():
img.save("a/non_existant/file_path")


def test_non_ascii_file_name():
"""
Can use full Unicode on utf-8 filesystems only
e.g. OS-X and most Linux
Windows only supports ASCII at this point
"""
img = Image(width=400, height=400)

filename = outfile("file\u2014name_with_unicode.png") # u2014 is an EmDash
if sys.getfilesystemencoding() == 'utf-8':
# this should work
img.save(filename)
assert filename.exists()
else:
# other filesystem encodings raise an Exception
with pytest.raises(ValueError):
img.save(filename)


def test_init_simple_add_rgb():
"""
simplest possible initilization -- no preset color palette
Expand Down

0 comments on commit dd64edf

Please sign in to comment.