From: gary r. <gar...@gm...> - 2013-04-07 08:40:19
|
Hi, I haven't looked at this list for a long time, so hi to all the active devs. I just came across a problem in the image.py imsave() function. Problem: At an ipython --pylab prompt, typing a = rand(29,29) imsave('test.png', a) incorrectly generates a 28x28 pixel image. This happens for several array sizes (I initially saw it for 226x226). Line 1272 of image.py is figsize = [x / float(dpi) for x in (arr.shape[1], arr.shape[0])] figsize interacts with the bounding box code somehow to create off-by-one results for certain values of array shape. Possible solution: To fix this properly, I think the float cast should be removed and integer-based math should be used, but I thought that since it was rounding down in the cases I saw, a change to the following should fix this: figsize = [(x + 0.5) / float(dpi) for x in (arr.shape[1], arr.shape[0])] and indeed this seems to work. To verify this, I ran the following brute-force test of all image sizes up to 1024x1024 at some common dpi values: import matplotlib.pyplot as plt import numpy as np import os for dpi in [75, 100, 150, 300, 600, 1200]: for i in range(1,1025): print dpi, i, im = np.random.random((i,i)) fname = 'test{:03d}.png'.format(i) plt.imsave(fname, im, dpi=dpi) im = plt.imread(fname)[:,:,0] print im.shape assert im.shape == (i, i) os.remove(fname) and everything passed. For completeness I also explored the dpi-space with these loop ranges and the above loop body: for dpi in range(1, 101): for i in range(25, 36): ... and all was still well. Workaround: For the moment I've set dpi=1 in my call to imsave which effectively reverts its behaviour to the original imsave code prior to the introduction of the dpi parameter. I think this testing is rigorous enough to make this change. If you agree, has anyone got time to change this, or shall I do a pull request when I have time? thanks, Gary |