-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Discuss about other bindings implementation #51
Comments
My take:
|
If size is not specified or equals to 1, output values are stored in x and y, in x/y_array otherwise |
|
|
Future goal is to add the vips_resize binding in the JVips API. But we need to make some changes to avoid name conflicts because: * resize(width, height, scale) use the vips_thumbnail_image binding * resize(hscale, vscale, kernel) will use the vips_resize binding To avoid this conflict and to follow the JVips naming convention (criteo#51), I propose to deprecate the resize method in favor of new thumbnailImage. See criteo#72
Future goal is to add the vips_resize binding in the JVips API. But we need to make some changes to avoid name conflicts because: * resize(width, height, scale) use the vips_thumbnail_image binding * resize(hscale, vscale, kernel) will use the vips_resize binding To avoid this conflict and follow the JVips naming convention (criteo#51), I propose to deprecate the resize method in favor of a new thumbnailImage method. See criteo#72
Future goal is to add the vips_resize binding in the JVips API. But we need to make some changes to avoid name conflicts because: * resize(width, height, scale) use the vips_thumbnail_image binding * resize(hscale, vscale, kernel) will use the vips_resize binding To avoid this conflict and follow the JVips naming convention (#51), I propose to deprecate the resize method in favor of a new thumbnailImage method. See #72
Pardon me for jumping on in on this issue, but this has piqued my interest. I've built an experimental TypeScript program to parse the output of This is an example of the first function I've tried generating: JNIEXPORT void JNICALL
Java_com_criteo_vips_VipsImage_embed(JNIEnv *env, jobject in, jint x, jint y, jint width, jint height, jobject options)
{
GValue gvalue = { 0 };
VipsOperation *op = vips_operation_new("embed");
// in
g_value_init( &gvalue, VIPS_TYPE_IMAGE );
g_value_set_object(&gvalue, (VipsImage *) (*env)->GetLongField(env, in, handle_fid));
g_object_set_property(G_OBJECT(op), "in", &gvalue);
g_value_unset(&gvalue);
// x
g_value_init(&gvalue, G_TYPE_INT );
g_value_set_int(&gvalue, x);
g_object_set_property(G_OBJECT(op), "x", &gvalue);
g_value_unset(&gvalue);
// y
g_value_init(&gvalue, G_TYPE_INT );
g_value_set_int(&gvalue, y);
g_object_set_property(G_OBJECT(op), "y", &gvalue);
g_value_unset(&gvalue);
// width
g_value_init(&gvalue, G_TYPE_INT );
g_value_set_int(&gvalue, width);
g_object_set_property(G_OBJECT(op), "width", &gvalue);
g_value_unset(&gvalue);
// height
g_value_init(&gvalue, G_TYPE_INT );
g_value_set_int(&gvalue, height);
g_object_set_property(G_OBJECT(op), "height", &gvalue);
g_value_unset(&gvalue);
// Operation
VipsOperation *new_op;
if (!(new_op = vips_cache_operation_build(op))) {
g_object_unref(op);
vips_error_exit(NULL);
}
g_object_unref(op);
op = new_op;
// Image result
g_value_init(&gvalue, VIPS_TYPE_IMAGE);
g_object_get_property(G_OBJECT(op), "out", &gvalue);
VipsImage *_out = VIPS_IMAGE(g_value_get_object(&gvalue));
g_object_ref(_out);
g_value_unset(&gvalue);
g_object_unref((VipsImage *) (*env)->GetLongField(env, in, handle_fid));
(*env)->SetLongField(env, in, handle_fid, (jlong) _out);
// Free the operation
vips_object_unref_outputs(VIPS_OBJECT(op));
g_object_unref(op);
} I'd love to collaborate with you both on this if it piques your interest too. At the moment I think it's quite likely that we can automatically generate most of the implementation. |
A complete JNIEXPORT void JNICALL
Java_com_criteo_vips_VipsImage_thumbnailImageNative(JNIEnv *env, jobject in, jint width, jobject options)
{
GValue gvalue = { 0 };
VipsOperation *op = vips_operation_new("thumbnail_image");
// in
if (in != NULL) {
g_value_init(&gvalue, VIPS_TYPE_IMAGE);
g_value_set_object(&gvalue, (VipsImage *) (*env)->GetLongField(env, in, handle_fid));
g_object_set_property(G_OBJECT(op), "in", &gvalue);
g_value_unset(&gvalue);
}
// width
g_value_init(&gvalue, G_TYPE_INT);
g_value_set_int(&gvalue, width);
g_object_set_property(G_OBJECT(op), "width", &gvalue);
g_value_unset(&gvalue);
// Optionals
if (options != NULL) {
jclass optionsCls = (*env)->GetObjectClass(env, options);
// height
jfieldID heightFid = (*env)->GetFieldID(env, optionsCls, "height", "Ljava/lang/Integer;");
jobject heightObjectValue = (*env)->GetObjectField(env, options, heightFid);
if (heightObjectValue != NULL) {
jint height = (*env)->CallIntMethod(env, heightObjectValue, intValue_mid);
g_value_init(&gvalue, G_TYPE_INT);
g_value_set_int(&gvalue, height);
g_object_set_property(G_OBJECT(op), "height", &gvalue);
g_value_unset(&gvalue);
}
// size
jfieldID sizeFid = (*env)->GetFieldID(env, optionsCls, "size", "Lcom/criteo/vips/enums/VipsSize;");
jobject size = (*env)->GetObjectField(env, options, sizeFid);
if (size != NULL) {
jclass sizeCls = (*env)->GetObjectClass(env, size);
jfieldID sizeValueFid = (*env)->GetFieldID(env, sizeCls, "value", "I");
jint sizeValue = (*env)->GetIntField(env, size, sizeValueFid);
g_value_init(&gvalue, G_TYPE_INT);
g_value_set_int(&gvalue, sizeValue);
g_object_set_property(G_OBJECT(op), "size", &gvalue);
g_value_unset(&gvalue);
}
// no-rotate
jfieldID noRotateFid = (*env)->GetFieldID(env, optionsCls, "noRotate", "Ljava/lang/Boolean;");
jobject noRotateObjectValue = (*env)->GetObjectField(env, options, noRotateFid);
if (noRotateObjectValue != NULL) {
jboolean noRotate = (*env)->CallBooleanMethod(env, noRotateObjectValue, booleanValue_mid);
g_value_init(&gvalue, G_TYPE_BOOLEAN);
g_value_set_boolean(&gvalue, noRotate);
g_object_set_property(G_OBJECT(op), "no-rotate", &gvalue);
g_value_unset(&gvalue);
}
// crop
jfieldID cropFid = (*env)->GetFieldID(env, optionsCls, "crop", "Lcom/criteo/vips/enums/VipsInteresting;");
jobject crop = (*env)->GetObjectField(env, options, cropFid);
if (crop != NULL) {
jclass cropCls = (*env)->GetObjectClass(env, crop);
jfieldID cropValueFid = (*env)->GetFieldID(env, cropCls, "value", "I");
jint cropValue = (*env)->GetIntField(env, crop, cropValueFid);
g_value_init(&gvalue, G_TYPE_INT);
g_value_set_int(&gvalue, cropValue);
g_object_set_property(G_OBJECT(op), "crop", &gvalue);
g_value_unset(&gvalue);
}
// linear
jfieldID linearFid = (*env)->GetFieldID(env, optionsCls, "linear", "Ljava/lang/Boolean;");
jobject linearObjectValue = (*env)->GetObjectField(env, options, linearFid);
if (linearObjectValue != NULL) {
jboolean linear = (*env)->CallBooleanMethod(env, linearObjectValue, booleanValue_mid);
g_value_init(&gvalue, G_TYPE_BOOLEAN);
g_value_set_boolean(&gvalue, linear);
g_object_set_property(G_OBJECT(op), "linear", &gvalue);
g_value_unset(&gvalue);
}
// import-profile
jfieldID importProfileFid = (*env)->GetFieldID(env, optionsCls, "importProfile", "Ljava/lang/String;");
jstring importProfile = (jstring) (*env)->GetObjectField(env, options, importProfileFid);
if (importProfile != NULL) {
const char *importProfileChars = (*env)->GetStringUTFChars(env, importProfile, NULL);
g_value_init(&gvalue, G_TYPE_STRING);
g_value_set_string(&gvalue, importProfileChars);
(*env)->ReleaseStringUTFChars(env, importProfile, importProfileChars);
g_object_set_property(G_OBJECT(op), "import-profile", &gvalue);
g_value_unset(&gvalue);
}
// export-profile
jfieldID exportProfileFid = (*env)->GetFieldID(env, optionsCls, "exportProfile", "Ljava/lang/String;");
jstring exportProfile = (jstring) (*env)->GetObjectField(env, options, exportProfileFid);
if (exportProfile != NULL) {
const char *exportProfileChars = (*env)->GetStringUTFChars(env, exportProfile, NULL);
g_value_init(&gvalue, G_TYPE_STRING);
g_value_set_string(&gvalue, exportProfileChars);
(*env)->ReleaseStringUTFChars(env, exportProfile, exportProfileChars);
g_object_set_property(G_OBJECT(op), "export-profile", &gvalue);
g_value_unset(&gvalue);
}
// intent
jfieldID intentFid = (*env)->GetFieldID(env, optionsCls, "intent", "Lcom/criteo/vips/enums/VipsIntent;");
jobject intent = (*env)->GetObjectField(env, options, intentFid);
if (intent != NULL) {
jclass intentCls = (*env)->GetObjectClass(env, intent);
jfieldID intentValueFid = (*env)->GetFieldID(env, intentCls, "value", "I");
jint intentValue = (*env)->GetIntField(env, intent, intentValueFid);
g_value_init(&gvalue, G_TYPE_INT);
g_value_set_int(&gvalue, intentValue);
g_object_set_property(G_OBJECT(op), "intent", &gvalue);
g_value_unset(&gvalue);
}
}
// Operation
VipsOperation *new_op;
if (!(new_op = vips_cache_operation_build(op))) {
g_object_unref(op);
throwVipsException(env, "thumbnail_image failed");
return;
}
g_object_unref(op);
op = new_op;
// Mutating image result
g_value_init(&gvalue, VIPS_TYPE_IMAGE);
g_object_get_property(G_OBJECT(op), "out", &gvalue);
VipsImage *_out = VIPS_IMAGE(g_value_get_object(&gvalue));
g_object_ref(_out);
g_value_unset(&gvalue);
g_object_unref((VipsImage *) (*env)->GetLongField(env, in, handle_fid));
(*env)->SetLongField(env, in, handle_fid, (jlong) _out);
// Free the operation
vips_object_unref_outputs(VIPS_OBJECT(op));
g_object_unref(op);
} |
In case it's of interest to anyone in this thread - I recently shipped JVM libvips bindings that use the libvips GObject and operations API to generate ~100% operation coverage, using JDK 22's "FFM" feature: https://github.com/lopcode/vips-ffm I mention because there don't appear to have been any changes to this repo for a couple of years. But please feel free to delete this comment if the project is still active or you don't feel it's appropriate. Happy to answer any questions over there, and take feedback from users. And thanks for your efforts with JVips over the years. |
Hello,
The goal is to implement missing bindings. This non exhaustive list aims to report the axis of improvement, conventions and technical choices for the project.
I will update this task list once we agree on a solution:
Propositions
Stateless VipsImage
Actually, VipsImage object is a stateful object. It has a mutable state when some methods are invoked (e.g.: resize(), pad(), crop(), ...). The .NET wrapper has a different approach. Every image method returns a new image.
Should we keep the actual implementation or move to a stateless VipsImage?
How to handle the optional input arguments of some vips operation in java?
It returns either a single maximum or a array of maximum values (with the coordinates in both cases)
Status
max
variadic resultThe text was updated successfully, but these errors were encountered: