Skip to content

Commit 672196f

Browse files
Add Image.data() method
This gives direct access to the image data and should allow BasicIo to be removed from the Python interface in a year or two.
1 parent 2247a7e commit 672196f

File tree

6 files changed

+740
-18
lines changed

6 files changed

+740
-18
lines changed

CHANGELOG.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ Changes in v0.18.0:
3535
7/ Exiv2 struct member names with a trailing underscore have more Pythonic
3636
aliases without the underscore.
3737
8/ Add data() method to exiv2.PreviewImage, deprecate pData() method.
38-
9/ BasicIo.read (& readOrThrow) now extract count from the buffer size.
39-
10/ Invalidate data iterators if data is deleted. (Requires swig >= 4.4)
40-
11/ Add __members__ attribute to exiv2 "data" structure types.
38+
9/ Add data() method to exiv2.Image. This will replace using Image.io().
39+
10/ BasicIo.read (& readOrThrow) now extract count from the buffer size.
40+
11/ Invalidate data iterators if data is deleted. (Requires swig >= 4.4)
4141
12/ Deprecated iteration of exiv2 "data" structure types.
4242
13/ API CHANGE: exiv2.LogMsg.pythonHandler is replaced by exiv2.pythonHandler
4343

USAGE.rst

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -401,28 +401,19 @@ The buffered data isn't actually read until ``Image::readMetadata`` is called, s
401401
When ``Image::writeMetadata`` is called exiv2 allocates a new block of memory to store the modified data.
402402
The ``Image::io`` method returns an `Exiv2::BasicIo`_ object that provides access to this data.
403403

404-
The ``BasicIo::mmap`` and ``BasicIo::munmap`` methods allows access to the image file data without unnecessary copying.
404+
The ``BasicIo::mmap`` and ``BasicIo::munmap`` methods allow access to the image file data without unnecessary copying.
405405
However they are rather error prone, crashing your Python program with a segmentation fault if anything goes wrong.
406-
Since python-exiv2 v0.18.0 it is much easier to use the ``data()`` method:
406+
407+
Since python-exiv2 v0.18.0 it is much easier to use the image's ``data()`` method:
407408

408409
.. code:: python
409410
410411
# after setting some metadata
411412
image.writeMetadata()
412-
exiv_io = image.io()
413-
rsp = requests.post(url, files={'file': io.BytesIO(exiv_io.data())})
414-
415-
The ``data()`` method can also return a writeable memoryview_:
416-
417-
.. code:: python
418-
419-
exiv_io = image.io()
420-
data = exiv_io.data(True)
421-
data[23] = 157 # modifies data buffer
422-
del data # writes modified data to the buffer
423-
image.readMetadata() # reads modified buffer data
413+
rsp = requests.post(url, files={'file': io.BytesIO(image.data())})
424414
425-
The modified data is written back to the file or memory buffer when the memoryview_ is deleted.
415+
The ``data()`` method returns a Python memoryview_ that can be used in most places where a `bytes-like object`_ is expected.
416+
This allows copy free access to the image data.
426417

427418
.. _bytearray:
428419
https://docs.python.org/3/library/stdtypes.html#bytearray

src/interface/image.i

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,46 @@ INPUT_BUFFER_RO(const Exiv2::byte* data, BUFLEN_T size,
7676
// Release memory buffer after writeMetadata, as it creates its own copy
7777
RELEASE_BUFFER(void writeMetadata)
7878

79+
// Add Image::data() method for easy data access to image data
80+
%feature("docstring") Exiv2::Image::data
81+
"Easy access to the image data.
82+
83+
Calls io().open() & io().mmap() and returns a Python memoryview of the
84+
data. io().munmap() & io().close() are called when the memoryview object
85+
is deleted.
86+
87+
This is intended to replace using Image.io() to get a BasicIo object,
88+
then accessing its data. BasicIo will eventually be removed from the
89+
Python interface.
90+
91+
:rtype: memoryview"
92+
%extend Exiv2::Image {
93+
%fragment("memoryview_funcs");
94+
PyObject* data(PyObject* py_self) {
95+
Exiv2::BasicIo& io = self->io();
96+
SWIG_PYTHON_THREAD_BEGIN_ALLOW;
97+
io.open();
98+
Exiv2::byte* ptr = io.mmap(false);
99+
SWIG_PYTHON_THREAD_END_ALLOW;
100+
PyObject* result = PyMemoryView_FromMemory(
101+
(char*)ptr, io.size(), PyBUF_READ);
102+
if (store_view(py_self, result))
103+
return NULL;
104+
return result;
105+
}
106+
}
107+
%fragment("release_ptr"{Exiv2::BasicIo});
108+
DEFINE_VIEW_CALLBACK(Exiv2::Image, release_ptr(&self->io());)
109+
%{
110+
#define RELEASE_VIEWS_Image_readMetadata
111+
#define RELEASE_VIEWS_Image_writeMetadata
112+
%}
113+
%typemap(check, fragment="memoryview_funcs") Exiv2::Image* self {
114+
%#ifdef RELEASE_VIEWS_$symname
115+
release_views(self);
116+
%#endif
117+
}
118+
79119
// Convert path encoding on Windows
80120
WINDOWS_PATH(const std::string& path)
81121

0 commit comments

Comments
 (0)