@@ -78,6 +78,11 @@ def self.p2str(pointer)
7878 class Image < Vips ::Object
7979 alias_method :parent_get_typeof , :get_typeof
8080
81+ # FFI sets a pointer's size to this magic value if the size of the memory
82+ # chunk the pointer points to is unknown to FFI.
83+ UNKNOWN_POINTER_SIZE = FFI ::Pointer . new ( 1 ) . size
84+ private_constant :UNKNOWN_POINTER_SIZE
85+ 8186 private
8287
8388 # the layout of the VipsImage struct
@@ -326,6 +331,24 @@ def self.new_from_buffer data, option_string, **opts
326331 # image.width, image.height, image.bands, image.format
327332 # ```
328333 #
334+ # Creating a new image from a memory pointer:
335+ #
336+ # ```
337+ # ptr = FFI::MemoryPointer.new(:uchar, 10*10)
338+ # # => #<FFI::MemoryPointer address=0x00007fc236db31d0 size=100>
339+ # x = Vips::Image.new_from_memory(ptr, 10, 10, 1, :uchar)
340+ # ```
341+ #
342+ # Creating a new image from an address only pointer:
343+ #
344+ # ```
345+ # ptr = call_to_external_c_library(w: 10, h: 10)
346+ # # => #<FFI::Pointer address=0x00007f9780813a00>
347+ # ptr_slice = ptr.slice(0, 10*10)
348+ # # => #<FFI::Pointer address=0x00007f9780813a00 size=100>
349+ # x = Vips::Image.new_from_memory(ptr_slice, 10, 10, 1, :uchar)
350+ # ```
351+ #
329352 # {new_from_memory} keeps a reference to the array of pixels you pass in
330353 # to try to prevent that memory from being freed by the Ruby GC while it
331354 # is being used.
@@ -340,13 +363,23 @@ def self.new_from_buffer data, option_string, **opts
340363 # @param format [Symbol] band format
341364 # @return [Image] the loaded image
342365 def self . new_from_memory data , width , height , bands , format
343- size = data . bytesize
344- 345366 # prevent data from being freed with JRuby FFI
346367 if defined? ( JRUBY_VERSION ) && !data . is_a? ( FFI ::Pointer )
347368 data = ::FFI ::MemoryPointer . new ( :char , data . bytesize ) . write_bytes data
348369 end
349370
371+ if data . is_a? ( FFI ::Pointer )
372+ # A pointer needs to know about the size of the memory it points to.
373+ # If you have an address-only pointer, use the .slice method to wrap
374+ # the pointer in a size aware pointer.
375+ if data . size == UNKNOWN_POINTER_SIZE
376+ raise Vips ::Error , "size of memory is unknown"
377+ end
378+ size = data . size
379+ else
380+ size = data . bytesize
381+ end
382+ 350383 format_number = GObject ::GValue . from_nick BAND_FORMAT_TYPE , format
351384 vi = Vips . vips_image_new_from_memory data , size ,
352385 width , height , bands , format_number
@@ -373,7 +406,17 @@ def self.new_from_memory data, width, height, bands, format
373406 # @return [Image] the loaded image
374407 def self . new_from_memory_copy data , width , height , bands , format
375408 format_number = GObject ::GValue . from_nick BAND_FORMAT_TYPE , format
376- vi = Vips . vips_image_new_from_memory_copy data , data . bytesize ,
409+ 410+ if data . is_a? ( FFI ::Pointer )
411+ if data . size == UNKNOWN_POINTER_SIZE
412+ raise Vips ::Error , "size of memory is unknown"
413+ end
414+ size = data . size
415+ else
416+ size = data . bytesize
417+ end
418+ 419+ vi = Vips . vips_image_new_from_memory_copy data , size ,
377420 width , height , bands , format_number
378421 raise Vips ::Error if vi . null?
379422 new ( vi )
0 commit comments