@@ -78,6 +78,11 @@ def self.p2str(pointer)
78
78
class Image < Vips ::Object
79
79
alias_method :parent_get_typeof , :get_typeof
80
80
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
+
81
86
private
82
87
83
88
# the layout of the VipsImage struct
@@ -326,6 +331,24 @@ def self.new_from_buffer data, option_string, **opts
326
331
# image.width, image.height, image.bands, image.format
327
332
# ```
328
333
#
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
+ #
329
352
# {new_from_memory} keeps a reference to the array of pixels you pass in
330
353
# to try to prevent that memory from being freed by the Ruby GC while it
331
354
# is being used.
@@ -340,13 +363,23 @@ def self.new_from_buffer data, option_string, **opts
340
363
# @param format [Symbol] band format
341
364
# @return [Image] the loaded image
342
365
def self . new_from_memory data , width , height , bands , format
343
- size = data . bytesize
344
-
345
366
# prevent data from being freed with JRuby FFI
346
367
if defined? ( JRUBY_VERSION ) && !data . is_a? ( FFI ::Pointer )
347
368
data = ::FFI ::MemoryPointer . new ( :char , data . bytesize ) . write_bytes data
348
369
end
349
370
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
+
350
383
format_number = GObject ::GValue . from_nick BAND_FORMAT_TYPE , format
351
384
vi = Vips . vips_image_new_from_memory data , size ,
352
385
width , height , bands , format_number
@@ -373,7 +406,17 @@ def self.new_from_memory data, width, height, bands, format
373
406
# @return [Image] the loaded image
374
407
def self . new_from_memory_copy data , width , height , bands , format
375
408
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 ,
377
420
width , height , bands , format_number
378
421
raise Vips ::Error if vi . null?
379
422
new ( vi )
0 commit comments