diff --git a/pyopencl/c_wrapper/wrap_cl_core.h b/pyopencl/c_wrapper/wrap_cl_core.h
index 8210ba3395964f9ec9ae6ac3fcd3f929de5ec7f6..58649e62ab962fe686bac06f916c4aa804478f89 100644
--- a/pyopencl/c_wrapper/wrap_cl_core.h
+++ b/pyopencl/c_wrapper/wrap_cl_core.h
@@ -163,10 +163,18 @@ error *enqueue_fill_buffer(clobj_t *_evt, clobj_t _queue, clobj_t _mem,
                            uint32_t num_wait_for);
 // enqueue_*_image*
 error *enqueue_read_image(clobj_t *event, clobj_t queue, clobj_t mem,
-                          size_t *origin, size_t *region, void *buffer,
-                          size_t row_pitch, size_t slice_pitch,
+                          const size_t *origin, size_t origin_l,
+                          const size_t *region, size_t region_l,
+                          void *buffer, size_t row_pitch, size_t slice_pitch,
                           const clobj_t *wait_for, uint32_t num_wait_for,
                           int is_blocking, void (*ref)(unsigned long));
+error *enqueue_write_image(clobj_t *_evt, clobj_t _queue, clobj_t _mem,
+                           const size_t *origin, size_t origin_l,
+                           const size_t *region, size_t region_l,
+                           const void *buffer, size_t row_pitch,
+                           size_t slice_pitch, const clobj_t *_wait_for,
+                           uint32_t num_wait_for, int is_blocking,
+                           void (*ref)(unsigned long));
 // CL Object
 intptr_t clobj__int_ptr(clobj_t obj);
 error *clobj__get_info(clobj_t obj, cl_uint param, generic_info *out);
diff --git a/pyopencl/cffi_cl.py b/pyopencl/cffi_cl.py
index 233e1a0336e7a4c1f6b3d7b74d4c65f5a54bca7c..846aab5eab347f60f267c5da5c332a15d9a74609 100644
--- a/pyopencl/cffi_cl.py
+++ b/pyopencl/cffi_cl.py
@@ -906,16 +906,38 @@ def _enqueue_fill_buffer(queue, mem, pattern, offset, size, wait_for=None):
 
 def _enqueue_read_image(queue, mem, origin, region, hostbuf, row_pitch=0,
                         slice_pitch=0, wait_for=None, is_blocking=True):
+    origin_l = len(origin)
+    region_l = len(region)
+    if origin_l > 3 or region_l > 3:
+        raise RuntimeError("origin or region has too many components",
+                           "enqueue_read_image")
     c_buf, size, _ = _c_buffer_from_obj(hostbuf, writable=True)
     ptr_event = _ffi.new('clobj_t*')
     c_wait_for, num_wait_for = _clobj_list(wait_for)
     # TODO check buffer size
     _handle_error(_lib.enqueue_read_image(
-        ptr_event, queue.ptr, mem.ptr, origin, region, c_buf, row_pitch,
-        slice_pitch, c_wait_for, num_wait_for, bool(is_blocking),
-        _get_ref_func(c_buf)))
+        ptr_event, queue.ptr, mem.ptr, origin, origin_l, region, region_l,
+        c_buf, row_pitch, slice_pitch, c_wait_for, num_wait_for,
+        bool(is_blocking), _get_ref_func(c_buf)))
     return _create_instance(NannyEvent, ptr_event[0])
 
+def _enqueue_write_image(queue, mem, origin, region, hostbuf, row_pitch=0,
+                         slice_pitch=0, wait_for=None, is_blocking=True):
+    origin_l = len(origin)
+    region_l = len(region)
+    if origin_l > 3 or region_l > 3:
+        raise RuntimeError("origin or region has too many components",
+                           "enqueue_read_image")
+    c_buf, size, _ = _c_buffer_from_obj(hostbuf)
+    _event = _ffi.new('clobj_t*')
+    c_wait_for, num_wait_for = _clobj_list(wait_for)
+    # TODO check buffer size
+    _handle_error(_lib.enqueue_read_image(
+        _event, queue.ptr, mem.ptr, origin, origin_l, region, region_l,
+        c_buf, row_pitch, slice_pitch, c_wait_for, num_wait_for,
+        bool(is_blocking), _get_ref_func(c_buf)))
+    return _create_instance(NannyEvent, _event[0])
+
 # TODO: write_image copy_image fill_image
 #    copy_buffer_to_image copy_image_to_buffer
 
diff --git a/src/c_wrapper/wrap_cl.cpp b/src/c_wrapper/wrap_cl.cpp
index e1796b2618120528e997f238bd0c09c6fdf98ac1..cf3d56b4b6550e964cc94e8d612e259c48ca8736 100644
--- a/src/c_wrapper/wrap_cl.cpp
+++ b/src/c_wrapper/wrap_cl.cpp
@@ -2450,7 +2450,7 @@ enqueue_barrier(clobj_t _queue)
         });
 }
 
-// {{{ transfer enqueues
+// {{{ enqueue_*_buffer*
 
 error*
 enqueue_read_buffer(clobj_t *_evt, clobj_t _queue, clobj_t _mem,
@@ -2579,16 +2579,31 @@ enqueue_fill_buffer(clobj_t *_evt, clobj_t _queue, clobj_t _mem, void *pattern,
         });
 }
 
+// }}}
+
+// {{{ enqueue_*_image*
+
 error*
-enqueue_read_image(clobj_t *_evt, clobj_t _queue, clobj_t _mem, size_t *origin,
-                   size_t *region, void *buffer, size_t row_pitch,
-                   size_t slice_pitch, const clobj_t *_wait_for,
-                   uint32_t num_wait_for, int is_blocking,
-                   void (*ref)(unsigned long))
+enqueue_read_image(clobj_t *_evt, clobj_t _queue, clobj_t _mem,
+                   const size_t *origin, size_t origin_l,
+                   const size_t *region, size_t region_l, void *buffer,
+                   size_t row_pitch, size_t slice_pitch,
+                   const clobj_t *_wait_for, uint32_t num_wait_for,
+                   int is_blocking, void (*ref)(unsigned long))
 {
     auto wait_for = buf_from_class<event>(_wait_for, num_wait_for);
     auto queue = static_cast<command_queue*>(_queue);
     auto img = static_cast<image*>(_mem);
+    size_t _origin[3] = {0};
+    if (origin_l < 3) {
+        memcpy(_origin, origin, sizeof(size_t) * origin_l);
+        origin = _origin;
+    }
+    size_t _region[3] = {0};
+    if (region_l < 3) {
+        memcpy(_region, region, sizeof(size_t) * region_l);
+        region = _region;
+    }
     return c_handle_error([&] {
             cl_event evt;
             retry_mem_error<void>([&] {
@@ -2602,6 +2617,40 @@ enqueue_read_image(clobj_t *_evt, clobj_t _queue, clobj_t _mem, size_t *origin,
         });
 }
 
+error*
+enqueue_write_image(clobj_t *_evt, clobj_t _queue, clobj_t _mem,
+                    const size_t *origin, size_t origin_l,
+                    const size_t *region, size_t region_l,
+                    const void *buffer, size_t row_pitch, size_t slice_pitch,
+                    const clobj_t *_wait_for, uint32_t num_wait_for,
+                    int is_blocking, void (*ref)(unsigned long))
+{
+    auto wait_for = buf_from_class<event>(_wait_for, num_wait_for);
+    auto queue = static_cast<command_queue*>(_queue);
+    auto img = static_cast<image*>(_mem);
+    size_t _origin[3] = {0};
+    if (origin_l < 3) {
+        memcpy(_origin, origin, sizeof(size_t) * origin_l);
+        origin = _origin;
+    }
+    size_t _region[3] = {0};
+    if (region_l < 3) {
+        memcpy(_region, region, sizeof(size_t) * region_l);
+        region = _region;
+    }
+    return c_handle_error([&] {
+            cl_event evt;
+            retry_mem_error<void>([&] {
+                    pyopencl_call_guarded(
+                        clEnqueueWriteImage, queue->data(), img->data(),
+                        cast_bool(is_blocking), origin, region, row_pitch,
+                        slice_pitch, buffer, num_wait_for,
+                        wait_for.get(), &evt);
+                });
+            *_evt = new_nanny_event(evt, ref);
+        });
+}
+
 // }}}
 
 intptr_t