[python-imageio] 01/02: Import python-imageio_2.1.2+ds1.orig.tar.gz

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Sun Jun 4 11:06:07 UTC 2017


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to tag patched/2.1.2+ds1-1
in repository python-imageio.

commit 8af6d67a85135ceb373e80a4d668719793363f91
Author: Ghislain Antony Vaillant <ghisvail at gmail.com>
Date:   Fri Feb 17 12:54:16 2017 +0000

    Import python-imageio_2.1.2+ds1.orig.tar.gz
---
 PKG-INFO                       |  2 +-
 docs/releasenotes.rst          | 21 +++++++++++++++++++++
 imageio/__init__.py            |  2 +-
 imageio/core/__init__.py       |  2 +-
 imageio/core/format.py         | 15 ++++++++++++++-
 imageio/core/request.py        | 38 +++++++++++++++++++++++++++++++++++++-
 imageio/plugins/ffmpeg.py      | 37 +++++++++++++++----------------------
 imageio/plugins/pillowmulti.py | 14 +++++++++++---
 tests/test_ffmpeg.py           | 17 +++++++++++++++++
 tests/test_pillow.py           | 10 +++++++++-
 10 files changed, 127 insertions(+), 31 deletions(-)

diff --git a/PKG-INFO b/PKG-INFO
index 232e30c..fc8f06e 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: imageio
-Version: 2.1.1
+Version: 2.1.2
 Summary: Library for reading and writing a wide range of image, video, scientific, and volumetric data formats.
 Home-page: http://imageio.github.io/
 Author: imageio contributors
diff --git a/docs/releasenotes.rst b/docs/releasenotes.rst
index 98c6995..f75d480 100644
--- a/docs/releasenotes.rst
+++ b/docs/releasenotes.rst
@@ -2,6 +2,27 @@
 Release notes
 -------------
 
+
+Version 2.1.2 (02-02-2017)
+==========================
+
+A bugfix release:
+
+* Fix animated gif writer that was broken in newer Pillow version.
+* FFMPEG plugin improvements: more reliable fps detection, can deal
+  with missing FPS, more reliable subprocess termination,
+* Mimread allows a few missing frames to better deal with certain video files.
+* Allow question marks in url's.
+* Allow Pillow plugin to read remote files by "enabling" ``seek()`` and ``tell()``.
+* Use invoke to run development tasks instead of custom "make" module.
+
+
+Version 2.1.1 (24-12-2016)
+=========================
+
+Minor improvements related to Debian packaging.
+
+
 Version 2.1 (22-12-2016)
 ========================
 
diff --git a/imageio/__init__.py b/imageio/__init__.py
index 252aa54..f859bbe 100644
--- a/imageio/__init__.py
+++ b/imageio/__init__.py
@@ -16,7 +16,7 @@ Main website: http://imageio.github.io
 
 # flake8: noqa
 
-__version__ = '2.1.1'
+__version__ = '2.1.2'
 
 # Load some bits from core
 from .core import FormatManager, RETURN_BYTES
diff --git a/imageio/core/__init__.py b/imageio/core/__init__.py
index 3f6d449..622b9c4 100644
--- a/imageio/core/__init__.py
+++ b/imageio/core/__init__.py
@@ -15,4 +15,4 @@ from .util import get_platform, appdata_dir, resource_dirs, has_module
 from .findlib import load_lib
 from .fetching import get_remote_file, InternetNotAllowedError, NeedDownloadError
 from .request import Request, read_n_bytes, RETURN_BYTES
-from .format import Format, FormatManager
+from .format import Format, FormatManager, CannotReadFrameError
diff --git a/imageio/core/format.py b/imageio/core/format.py
index 3e7565a..1adcdec 100644
--- a/imageio/core/format.py
+++ b/imageio/core/format.py
@@ -35,6 +35,7 @@ from __future__ import absolute_import, print_function, division
 from __future__ import with_statement
 
 import os
+from warnings import warn
 
 import numpy as np
 
@@ -42,6 +43,14 @@ from . import Image, asarray
 from . import string_types, text_type, binary_type  # noqa
 
 
+class CannotReadFrameError(RuntimeError):
+    """ Exception to be used by plugins to indicate that a frame could not
+    be read, even though it should be a valid index. The length could be
+    inf, or e.g. video sometimes reports a wrong length.
+    """
+    pass
+
+
 class Format(object):
     """ Represents an implementation to read/write a particular file format
     
@@ -375,9 +384,13 @@ class Format(object):
             while i < n:
                 try:
                     im, meta = self._get_data(i)
-                except IndexError:
+                except (IndexError, CannotReadFrameError):
                     if n == float('inf'):
                         return
+                    elif n - i == 1:
+                        uri = self.request.filename
+                        warn('Could not read last frame of %s.' % uri)
+                        return
                     raise
                 yield Image(im, meta)
                 i += 1
diff --git a/imageio/core/request.py b/imageio/core/request.py
index d9d0147..bc07b25 100644
--- a/imageio/core/request.py
+++ b/imageio/core/request.py
@@ -326,6 +326,7 @@ class Request(object):
         elif self._uri_type in [URI_HTTP or URI_FTP]:
             assert not want_to_write  # This should have been tested in init
             self._file = urlopen(self.filename, timeout=5)
+            fix_HTTPResponse(self._file)
         
         return self._file
     
@@ -340,7 +341,10 @@ class Request(object):
             return self._filename
         else:
             # Get filename
-            ext = os.path.splitext(self._filename)[1]
+            if self._uri_type in (URI_HTTP, URI_FTP):
+                ext = os.path.splitext(self._filename.split('?')[0])[1]
+            else:
+                ext = os.path.splitext(self._filename)[1]
             self._filename_local = tempfile.mktemp(ext, 'imageio_')
             # Write stuff to it?
             if self.mode[0] == 'r':
@@ -455,3 +459,35 @@ def read_n_bytes(f, N):
             break
         bb += extra_bytes
     return bb
+
+
+def fix_HTTPResponse(f):
+    """This fixes up an HTTPResponse object so that it can tell(), and also
+    seek() will work if its effectively a no-op. This allows tools like Pillow
+    to use the file object.
+    """
+    count = [0]
+    
+    def read(n=None):
+        res = ori_read(n)
+        count[0] += len(res)
+        return res
+    
+    def tell():
+        return count[0]
+    
+    def seek(i, mode=0):
+        if not (mode == 0 and i == count[0]):
+            ori_seek(i, mode)
+    
+    def fail_seek(i, mode=0):
+        raise RuntimeError('No seeking allowed!')
+    
+    # Note, there is currently no protection from wrapping an object more than
+    # once, it will (probably) work though, because closures.
+    ori_read = f.read
+    ori_seek = f.seek if hasattr(f, 'seek') else fail_seek
+    
+    f.read = read
+    f.tell = tell
+    f.seek = seek
diff --git a/imageio/plugins/ffmpeg.py b/imageio/plugins/ffmpeg.py
index 5e7f5b9..5199b79 100644
--- a/imageio/plugins/ffmpeg.py
+++ b/imageio/plugins/ffmpeg.py
@@ -25,7 +25,7 @@ import numpy as np
 
 from .. import formats
 from ..core import (Format, get_remote_file, string_types, read_n_bytes,
-                    image_as_uint, get_platform,
+                    image_as_uint, get_platform, CannotReadFrameError,
                     InternetNotAllowedError, NeedDownloadError)
 
 FNAME_PER_PLATFORM = {
@@ -309,7 +309,7 @@ class FfmpegFormat(Format):
                                                    framesize)
 
         def _close(self):
-            self._terminate(0.05)  # Short timeout
+            self._terminate()  # Short timeout
             self._proc = None
 
         def _get_length(self):
@@ -404,7 +404,7 @@ class FfmpegFormat(Format):
                 # Create thread that keeps reading from stderr
                 self._stderr_catcher = StreamCatcher(self._proc.stderr)
 
-        def _terminate(self, timeout=1.0):
+        def _terminate(self):
             """ Terminate the sub process.
             """
             # Check
@@ -413,26 +413,16 @@ class FfmpegFormat(Format):
             if self._proc.poll() is not None:
                 return  # process already dead
             # Terminate process
-            self._proc.terminate()
+            # Using kill since self._proc.terminate() does not seem
+            # to work for ffmpeg, leaves processes hanging
+            self._proc.kill()
+
             # Tell threads to stop when they have a chance. They are probably
             # blocked on reading from their file, but let's play it safe.
             if self._stderr_catcher:
                 self._stderr_catcher.stop_me()
             if self._frame_catcher:
                 self._frame_catcher.stop_me()
-            # Close stdin as another way to tell ffmpeg that we're done. Don't
-            # close other streams, because it causes issue #174
-            try:
-                self._proc.stdin.close()
-            except Exception:  # pragma: no cover
-                pass
-            # Wait for it to close (but do not get stuck)
-            etime = time.time() + timeout
-            while time.time() < etime:
-                time.sleep(0.01)
-                if self._proc.poll() is not None:
-                    return
-            # self._proc.kill()  # probably not needed ...
 
         def _load_infos(self):
             """ reads the FFMPEG info on the file and sets size fps
@@ -481,10 +471,12 @@ class FfmpegFormat(Format):
             # get the output line that speaks about video
             videolines = [l for l in lines if ' Video: ' in l]
             line = videolines[0]
-
+            
             # get the frame rate
-            match = re.search("( [0-9]*.| )[0-9]* (tbr|fps)", line)
-            fps = float(line[match.start():match.end()].split(' ')[1])
+            matches = re.findall(" ([0-9]+\.?[0-9]*) (tbr|fps)", line)
+            fps = 0
+            if matches:  # Can be empty, see #171, assume nframes = inf
+                fps = float(matches[0][0].strip())
             self._meta['fps'] = fps
 
             # get the size of the original stream, of the form 460x320 (w x h)
@@ -512,7 +504,8 @@ class FfmpegFormat(Format):
             if match is not None:
                 hms = map(float, line[match.start()+1:match.end()].split(':'))
                 self._meta['duration'] = duration = cvsecs(*hms)
-                self._meta['nframes'] = int(round(duration*fps))
+                if fps:
+                    self._meta['nframes'] = int(round(duration*fps))
 
         def _read_frame_data(self):
             # Init and check
@@ -533,7 +526,7 @@ class FfmpegFormat(Format):
                 err1 = str(err)
                 err2 = self._stderr_catcher.get_text(0.4)
                 fmt = 'Could not read frame:\n%s\n=== stderr ===\n%s'
-                raise RuntimeError(fmt % (err1, err2))
+                raise CannotReadFrameError(fmt % (err1, err2))
             return s
 
         def _skip_frames(self, n=1):
diff --git a/imageio/plugins/pillowmulti.py b/imageio/plugins/pillowmulti.py
index ecf98dc..abb5120 100644
--- a/imageio/plugins/pillowmulti.py
+++ b/imageio/plugins/pillowmulti.py
@@ -156,6 +156,7 @@ class GifWriter:
             self.write_header(im_pil, palette, self.opt_loop)
             self._global_palette = palette
         self.write_image(im_pil, palette, rect, duration, dispose)
+        # assert len(palette) == len(self._global_palette)
         
         # Bookkeeping
         self._previous_image = im
@@ -177,12 +178,19 @@ class GifWriter:
         
         fp = self.fp
         
-        # Gather info
+        # Gather local image header and data, using PIL's getdata. That
+        # function returns a list of bytes objects, but which parts are
+        # what has changed multiple times, so we put together the first
+        # parts until we have enough to form the image header.
         data = self.getdata(im)
-        imdes, data = b''.join(data[:-2]), data[-2:]
-        graphext = self.getGraphicsControlExt(duration, dispose)
+        imdes = b''
+        while data and len(imdes) < 11:
+            imdes += data.pop(0)
+        assert len(imdes) == 11
+        
         # Make image descriptor suitable for using 256 local color palette
         lid = self.getImageDescriptor(im, rect)
+        graphext = self.getGraphicsControlExt(duration, dispose)
 
         # Write local header
         if (palette != self._global_palette) or (dispose != 2):
diff --git a/tests/test_ffmpeg.py b/tests/test_ffmpeg.py
index ca61530..aef0b00 100644
--- a/tests/test_ffmpeg.py
+++ b/tests/test_ffmpeg.py
@@ -375,6 +375,23 @@ def show_in_visvis():
         vv.processEvents()
 
 
+def test_reverse_read(tmpdir):
+    need_internet()
+    # Ensure we can read a file in reverse without error.
+
+    tmpf = tmpdir.join('test_vid.mp4')
+    W = imageio.get_writer(str(tmpf))
+    for i in range(300):
+        W.append_data(np.zeros((64, 64, 3), np.uint8))
+    W.close()
+
+    W = imageio.get_reader(str(tmpf))
+    for i in range(len(W)-1, 0, -1):
+        print("reading", i)
+        W.get_data(i)
+    W.close()
+
+
 if __name__ == '__main__':
     run_tests_if_main()
     #reader = imageio.read('cockatoo.mp4', 'ffmpeg')
diff --git a/tests/test_pillow.py b/tests/test_pillow.py
index d2e4668..5bb5931 100644
--- a/tests/test_pillow.py
+++ b/tests/test_pillow.py
@@ -147,7 +147,15 @@ def test_png():
     assert s2 < s1
     im2 = imageio.imread(fnamebase + '1.png')
     assert im2.dtype == np.uint16
-    
+
+
+def test_png_remote():
+    # issue #202
+    need_internet()
+    im = imageio.imread('https://raw.githubusercontent.com/imageio/' +
+                        'imageio-binaries/master/images/astronaut.png')
+    assert im.shape == (512, 512, 3)
+
 
 def test_jpg():
     

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/python-imageio.git



More information about the debian-science-commits mailing list