ImageLoader: spawn one thread per image. fix #93

In the process of fixing #93, I realized that we were spawning new
threads to fetch images for each update (we only need one).
This commit is contained in:
Mathieu PATUREL
2019-11-16 15:54:22 +11:00
parent cf68b2c202
commit e462e8b3bc
6 changed files with 23 additions and 22 deletions

2
.gitattributes vendored
View File

@ -1,3 +1,3 @@
docs/ export-ignore docs/ export-ignore
resources/ resources/
!resources/*.base64 !resources/*.base64

View File

@ -1,7 +1,7 @@
# Why? # Why?
Why do you want to use fancy symbols in your standard monospace font? Obviously to have a fancy prompt like mine :-) Why do you want to use fancy symbols in your standard monospace font? Obviously to have a fancy prompt like mine :-)
![prompt](https://github.com/gabrielelana/awesome-terminal-fonts/raw/master/why.png) <!-- ![prompt](https://github.com/gabrielelana/awesome-terminal-fonts/raw/master/why.png) -->
And because when you live in a terminal a symbol can convey more informations in less space creating a dense and beautiful (for those who have a certain aesthetic taste) informative workspace And because when you live in a terminal a symbol can convey more informations in less space creating a dense and beautiful (for those who have a certain aesthetic taste) informative workspace

View File

@ -25,13 +25,6 @@ markdowner = Markdown(extras=["fenced-code-blocks", "cuddled-lists"])
# does it stupidly throw them out? (we could implement something of our own) # does it stupidly throw them out? (we could implement something of our own)
executor = concurrent.futures.ThreadPoolExecutor(max_workers=5) executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)
images_cache = {}
class LoadingError(Exception):
pass
def markdown2html(markdown, basepath, re_render, resources, viewport_width): def markdown2html(markdown, basepath, re_render, resources, viewport_width):
""" converts the markdown to html, loads the images and puts in base64 for sublime """ converts the markdown to html, loads the images and puts in base64 for sublime
to understand them correctly. That means that we are responsible for loading the to understand them correctly. That means that we are responsible for loading the
@ -59,12 +52,7 @@ def markdown2html(markdown, basepath, re_render, resources, viewport_width):
# realpath: simplify that paths so that we don't have duplicated caches # realpath: simplify that paths so that we don't have duplicated caches
path = os.path.realpath(os.path.expanduser(os.path.join(basepath, src))) path = os.path.realpath(os.path.expanduser(os.path.join(basepath, src)))
try: base64, (width, height) = get_base64_image(path, re_render, resources)
base64, (width, height) = get_base64_image(path, re_render)
except FileNotFoundError as e:
base64, (width, height) = resources["base64_404_image"]
except LoadingError:
base64, (width, height) = resources["base64_loading_image"]
img_element["src"] = base64 img_element["src"] = base64
if width > viewport_width: if width > viewport_width:
@ -100,8 +88,10 @@ def markdown2html(markdown, basepath, re_render, resources, viewport_width):
"<br/>", "<br />" "<br/>", "<br />"
) )
images_cache = {}
images_loading = []
def get_base64_image(path, re_render): def get_base64_image(path, re_render, resources):
""" Gets the base64 for the image (local and remote images). re_render is a """ Gets the base64 for the image (local and remote images). re_render is a
callback which is called when we finish loading an image from the internet callback which is called when we finish loading an image from the internet
to trigger an update of the preview (the image will then be loaded from the cache) to trigger an update of the preview (the image will then be loaded from the cache)
@ -109,13 +99,20 @@ def get_base64_image(path, re_render):
return base64_data, (width, height) return base64_data, (width, height)
""" """
def callback(path, future): def callback(path, resources, future):
# altering images_cache is "safe" to do because callback is called in the same # altering images_cache is "safe" to do because callback is called in the same
# thread as add_done_callback: # thread as add_done_callback:
# > Added callables are called in the order that they were added and are always # > Added callables are called in the order that they were added and are always
# > called in a thread belonging to the process that added them # > called in a thread belonging to the process that added them
# > --- Python docs # > --- Python docs
images_cache[path] = future.result() try:
images_cache[path] = future.result()
except urllib.error.HTTPError as e:
images_cache[path] = resources['base64_404_image']
print("Error loading {!r}: {!r}".format(path, e))
images_loading.remove(path)
# we render, which means this function will be called again, but this time, we # we render, which means this function will be called again, but this time, we
# will read from the cache # will read from the cache
re_render() re_render()
@ -124,8 +121,11 @@ def get_base64_image(path, re_render):
return images_cache[path] return images_cache[path]
if path.startswith("http://") or path.startswith("https://"): if path.startswith("http://") or path.startswith("https://"):
executor.submit(load_image, path).add_done_callback(partial(callback, path)) # FIXME: submiting a load of loaders, we should only have one
raise LoadingError() if path not in images_loading:
executor.submit(load_image, path).add_done_callback(partial(callback, path, resources))
images_loading.append(path)
return resources['base64_loading_image']
with open(path, "rb") as fhandle: with open(path, "rb") as fhandle:
image_content = fhandle.read() image_content = fhandle.read()

File diff suppressed because one or more lines are too long

View File

@ -26,6 +26,7 @@ def make_cache(image_name):
width, height = get_image_size(png) width, height = get_image_size(png)
png.seek(0) png.seek(0)
base64.write(bytes("{}\n{}\n".format(width, height), encoding="utf-8")) base64.write(bytes("{}\n{}\n".format(width, height), encoding="utf-8"))
base64.write(b'data:image/png;base64,')
base64.write(b64encode(png.read())) base64.write(b64encode(png.read()))

File diff suppressed because one or more lines are too long