Skip to content

Commit 74e6f9d

Browse files
authored
Add support for vips_image_new_from_memory (#159)
1 parent 2f97a93 commit 74e6f9d

File tree

14 files changed

+1074
-385
lines changed

14 files changed

+1074
-385
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ repositories {
2222
}
2323

2424
dependencies {
25-
implementation("app.photofox.vips-ffm:vips-ffm-core:1.7.0")
25+
implementation("app.photofox.vips-ffm:vips-ffm-core:1.7.1")
2626
}
2727
```
2828

core/src/main/java/app/photofox/vipsffm/VImage.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import java.lang.String;
5353
import java.lang.foreign.Arena;
5454
import java.lang.foreign.MemorySegment;
55+
import java.lang.foreign.ValueLayout;
5556
import java.util.ArrayList;
5657
import java.util.Arrays;
5758
import java.util.List;
@@ -9700,6 +9701,19 @@ public static VImage newFromBytes(Arena arena, byte[] bytes, VipsOption... optio
97009701
return newFromSource(arena, source, options);
97019702
}
97029703

9704+
/// Creates a new VImage from raw bytes, mapping directly to the `vips_image_new_from_memory` function, with some checks.
9705+
///
9706+
/// This is included for narrow use cases where you have image bytes representing partially supported image formats from another library (like DICOM), and you need a way to get them in to libvips without using the built-in source loaders.
9707+
/// Note that due to Java FFM limitations, a full copy to native memory must still be performed.
9708+
///
9709+
/// This is an advanced method - if possible, use [VImage#newFromFile] and friends instead. If you have bytes to load, you could use [VImage#newFromBytes].
9710+
public static VImage newFromMemory(Arena arena, byte[] bytes, int width, int height, int bands,
9711+
int format) throws VipsError {
9712+
var offHeapBytes = arena.allocateFrom(ValueLayout.JAVA_BYTE, bytes);
9713+
var imagePointer = VipsHelper.image_new_from_memory(arena, offHeapBytes, offHeapBytes.byteSize(), width, height, bands, format);
9714+
return new VImage(arena, imagePointer);
9715+
}
9716+
97039717
/// Creates a new VImage from an [InputStream]. This uses libvips' "custom streaming" feature and is
97049718
/// therefore quite efficient, avoiding the need to make extra full copies of the image's data.
97059719
/// You could, for example, use this function to create an image directly from an API call, thumbnail it,

core/src/main/java/app/photofox/vipsffm/VipsHelper.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,40 @@ public static MemorySegment image_new(Arena arena) throws VipsError {
10211021
return result;
10221022
}
10231023

1024+
/// Binding for:
1025+
/// ```c
1026+
/// VipsImage *vips_image_new_from_memory(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format)
1027+
/// ```
1028+
public static MemorySegment image_new_from_memory(Arena arena, MemorySegment data, long size,
1029+
int width, int height, int bands, int format) throws VipsError {
1030+
if(!VipsValidation.isValidPointer(data)) {
1031+
VipsValidation.throwInvalidInputError("vips_image_new_from_memory", "data");
1032+
}
1033+
var result = VipsRaw.vips_image_new_from_memory(data, size, width, height, bands, format);
1034+
if(!VipsValidation.isValidPointer(result)) {
1035+
VipsValidation.throwInvalidOutputError("vips_image_new_from_memory", "result");
1036+
}
1037+
result = result.reinterpret(arena, VipsRaw::g_object_unref);
1038+
return result;
1039+
}
1040+
1041+
/// Binding for:
1042+
/// ```c
1043+
/// VipsImage *vips_image_new_from_memory_copy(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format)
1044+
/// ```
1045+
public static MemorySegment image_new_from_memory_copy(Arena arena, MemorySegment data, long size,
1046+
int width, int height, int bands, int format) throws VipsError {
1047+
if(!VipsValidation.isValidPointer(data)) {
1048+
VipsValidation.throwInvalidInputError("vips_image_new_from_memory_copy", "data");
1049+
}
1050+
var result = VipsRaw.vips_image_new_from_memory_copy(data, size, width, height, bands, format);
1051+
if(!VipsValidation.isValidPointer(result)) {
1052+
VipsValidation.throwInvalidOutputError("vips_image_new_from_memory_copy", "result");
1053+
}
1054+
result = result.reinterpret(arena, VipsRaw::g_object_unref);
1055+
return result;
1056+
}
1057+
10241058
/// Binding for:
10251059
/// ```c
10261060
/// void vips_image_set_delete_on_close(VipsImage *image, gboolean delete_on_close)

core/src/main/java/app/photofox/vipsffm/jextract/VipsRaw.java

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6995,6 +6995,132 @@ public static MemorySegment vips_image_new() {
69956995
}
69966996
}
69976997

6998+
private static class vips_image_new_from_memory {
6999+
public static final FunctionDescriptor DESC = FunctionDescriptor.of(
7000+
VipsRaw.C_POINTER,
7001+
VipsRaw.C_POINTER,
7002+
VipsRaw.C_LONG,
7003+
VipsRaw.C_INT,
7004+
VipsRaw.C_INT,
7005+
VipsRaw.C_INT,
7006+
VipsRaw.C_INT
7007+
);
7008+
7009+
public static final MemorySegment ADDR = VipsRaw.findOrThrow("vips_image_new_from_memory");
7010+
7011+
public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
7012+
}
7013+
7014+
/**
7015+
* Function descriptor for:
7016+
* {@snippet lang=c :
7017+
* extern VipsImage *vips_image_new_from_memory(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format)
7018+
* }
7019+
*/
7020+
public static FunctionDescriptor vips_image_new_from_memory$descriptor() {
7021+
return vips_image_new_from_memory.DESC;
7022+
}
7023+
7024+
/**
7025+
* Downcall method handle for:
7026+
* {@snippet lang=c :
7027+
* extern VipsImage *vips_image_new_from_memory(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format)
7028+
* }
7029+
*/
7030+
public static MethodHandle vips_image_new_from_memory$handle() {
7031+
return vips_image_new_from_memory.HANDLE;
7032+
}
7033+
7034+
/**
7035+
* Address for:
7036+
* {@snippet lang=c :
7037+
* extern VipsImage *vips_image_new_from_memory(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format)
7038+
* }
7039+
*/
7040+
public static MemorySegment vips_image_new_from_memory$address() {
7041+
return vips_image_new_from_memory.ADDR;
7042+
}
7043+
7044+
/**
7045+
* {@snippet lang=c :
7046+
* extern VipsImage *vips_image_new_from_memory(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format)
7047+
* }
7048+
*/
7049+
public static MemorySegment vips_image_new_from_memory(MemorySegment data, long size, int width, int height, int bands, int format) {
7050+
var mh$ = vips_image_new_from_memory.HANDLE;
7051+
try {
7052+
if (TRACE_DOWNCALLS) {
7053+
traceDowncall("vips_image_new_from_memory", data, size, width, height, bands, format);
7054+
}
7055+
return (MemorySegment)mh$.invokeExact(data, size, width, height, bands, format);
7056+
} catch (Throwable ex$) {
7057+
throw new AssertionError("should not reach here", ex$);
7058+
}
7059+
}
7060+
7061+
private static class vips_image_new_from_memory_copy {
7062+
public static final FunctionDescriptor DESC = FunctionDescriptor.of(
7063+
VipsRaw.C_POINTER,
7064+
VipsRaw.C_POINTER,
7065+
VipsRaw.C_LONG,
7066+
VipsRaw.C_INT,
7067+
VipsRaw.C_INT,
7068+
VipsRaw.C_INT,
7069+
VipsRaw.C_INT
7070+
);
7071+
7072+
public static final MemorySegment ADDR = VipsRaw.findOrThrow("vips_image_new_from_memory_copy");
7073+
7074+
public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC);
7075+
}
7076+
7077+
/**
7078+
* Function descriptor for:
7079+
* {@snippet lang=c :
7080+
* extern VipsImage *vips_image_new_from_memory_copy(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format)
7081+
* }
7082+
*/
7083+
public static FunctionDescriptor vips_image_new_from_memory_copy$descriptor() {
7084+
return vips_image_new_from_memory_copy.DESC;
7085+
}
7086+
7087+
/**
7088+
* Downcall method handle for:
7089+
* {@snippet lang=c :
7090+
* extern VipsImage *vips_image_new_from_memory_copy(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format)
7091+
* }
7092+
*/
7093+
public static MethodHandle vips_image_new_from_memory_copy$handle() {
7094+
return vips_image_new_from_memory_copy.HANDLE;
7095+
}
7096+
7097+
/**
7098+
* Address for:
7099+
* {@snippet lang=c :
7100+
* extern VipsImage *vips_image_new_from_memory_copy(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format)
7101+
* }
7102+
*/
7103+
public static MemorySegment vips_image_new_from_memory_copy$address() {
7104+
return vips_image_new_from_memory_copy.ADDR;
7105+
}
7106+
7107+
/**
7108+
* {@snippet lang=c :
7109+
* extern VipsImage *vips_image_new_from_memory_copy(const void *data, size_t size, int width, int height, int bands, VipsBandFormat format)
7110+
* }
7111+
*/
7112+
public static MemorySegment vips_image_new_from_memory_copy(MemorySegment data, long size, int width, int height, int bands, int format) {
7113+
var mh$ = vips_image_new_from_memory_copy.HANDLE;
7114+
try {
7115+
if (TRACE_DOWNCALLS) {
7116+
traceDowncall("vips_image_new_from_memory_copy", data, size, width, height, bands, format);
7117+
}
7118+
return (MemorySegment)mh$.invokeExact(data, size, width, height, bands, format);
7119+
} catch (Throwable ex$) {
7120+
throw new AssertionError("should not reach here", ex$);
7121+
}
7122+
}
7123+
69987124
private static class vips_image_set_delete_on_close {
69997125
public static final FunctionDescriptor DESC = FunctionDescriptor.ofVoid(
70007126
VipsRaw.C_POINTER,

0 commit comments

Comments
 (0)