diff --git a/LICENSE b/LICENSE index 44a22a8..c0b8acc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ The MIT License (MIT) Copyright (c) 2015 Geert Barentsen +Copyright (c) 2015 Aleksa Sarai Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/k2flix/core.py b/k2flix/core.py index 61322a8..4744240 100644 --- a/k2flix/core.py +++ b/k2flix/core.py @@ -3,6 +3,7 @@ """"Create movies or animated gifs from Kepler Target Pixel Files. Author: Geert Barentsen +Contributor: Aleksa Sarai """ from __future__ import (absolute_import, division, print_function, unicode_literals) @@ -13,6 +14,7 @@ import imageio import argparse import numpy as np +import io import matplotlib matplotlib.use('Agg') @@ -26,6 +28,19 @@ from astropy.utils.console import ProgressBar from astropy import log +def find_renderer(fig): + if hasattr(fig.canvas, "get_renderer"): + # Some renderers are nice and just given us get_renderer. + renderer = fig.canvas.get_renderer() + else: + # We have to hack around ones that don't by printing the figure to a + # temporary file object. We can then access the Agg renderer which is + # cached after writing it. Yes, this is ugly but there isn't really + # another way around it. + fig.canvas.print_figure(io.BytesIO()) + renderer = fig._cachedRenderer + return renderer + class BadKeplerFrame(Exception): """Raised if a frame is empty.""" @@ -125,12 +140,15 @@ def annotated_image(self, frame=0, dpi=None, vmin=1, vmax=5000, if dpi is None: # Twitter timeline requires dimensions between 440x220 and 1024x512 dpi = 440 / float(flx.shape[0]) + # DPI needs to be a multiple of two for ffmpeg. + dpi += dpi % 2 fontsize = 3. * flx.shape[0] with warnings.catch_warnings(): warnings.filterwarnings('ignore', message="(.*)invalid value(.*)") flx[np.isnan(flx) | (flx < vmin)] = vmin # Create the frame - fig = pl.figure(figsize=flx.shape, dpi=dpi) + fig = pl.figure(figsize=flx.shape[::-1], dpi=dpi) + rendr = find_renderer(fig) ax = fig.add_subplot(111) ax.matshow(flx, aspect='auto', norm=LogNorm(vmin=vmin, vmax=vmax), @@ -154,6 +172,22 @@ def annotated_image(self, frame=0, dpi=None, vmin=1, vmax=5000, txt2.set_path_effects([path_effects.Stroke(linewidth=fontsize/6., foreground='black'), path_effects.Normal()]) + + # Get text size to make sure it doesn't overlap. + txt_bbox = txt.get_window_extent(rendr) + txt2_bbox = txt2.get_window_extent(rendr) + + # Then scale the figure to match. + old_size = fig.get_size_inches() + ratio = max((1 + margin) * ((txt_bbox.x1 - txt_bbox.x0) + + (txt2_bbox.x1 - txt2_bbox.x0)) / fig.dpi + 2, + old_size[0]) / old_size[0] + new_size = np.around(np.multiply(old_size, ratio)) + + # Size needs to be divisible by two for video. + new_size += np.mod(new_size, 2) + fig.set_size_inches(*new_size) + ax.set_xticks([]) ax.set_yticks([]) ax.axis('off')