class_docstr: Custom sources allow reading data from otherwise unsupported sources.
  Requires libvips `>= 8.9.0`.
  
  To use, create a SourceCustom object, then provide callbacks to
  :meth:`on_read` and :meth:`on_seek`.
docstr: Attach a read handler.
  
  The interface is exactly as io.read(). The handler is given a number
  of bytes to fetch, and should return a bytes-like object containing up
  to that number of bytes. If there is no more data available, it should
  return None.
docstr_tok: ["Attach","a","read","handler",".","The","interface","is","exactly","as","io.read","(",")",".","The","handler","is","given","a","number","of","bytes","to","fetch",",","and","should","return","a","bytes-like","object","containing","up","to","that","number","of","bytes",".","If","there","is","no","more","data","available",",","it","should","return","None","."]
code: def on_read(self, handler):
      """Attach a read handler.
  
      The interface is exactly as io.read(). The handler is given a number
      of bytes to fetch, and should return a bytes-like object containing up
      to that number of bytes. If there is no more data available, it should
      return None.
  
      """
  
      def interface_handler(buf):
          chunk = handler(len(buf))
          if chunk is None:
              return 0
  
          bytes_read = len(chunk)
          buf[:bytes_read] = chunk
  
          return bytes_read
  
      self.signal_connect("read", interface_handler)
  
file_path: pyvips/pyvips/vsourcecustom.py
imports: from __future__ import division
  import logging
  import pyvips
  from pyvips import ffi, vips_lib
label_desc: Use image node_id 2 for calling the SourceCustom obj's underlying member method code with example usage: obj.on_read(handler) and returns: bytes_read, int