Skip to content
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

Libvips 8.13 and GIF output support #139

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
project(JVIPS C Java)
cmake_minimum_required(VERSION 3.6.0)

set(JVIPS_VERSION 8.12.2)
set(JVIPS_VERSION 8.13.0)

set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${JVIPS_VERSION}")
set(CPACK_SOURCE_GENERATOR "TGZ")
Expand Down
30 changes: 29 additions & 1 deletion lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,33 @@ else()
add_custom_target(giflib "")
endif()

find_program(Meson_EXECUTABLE meson)
if(NOT Meson_EXECUTABLE)
message(FATAL_ERROR "Cooking: Meson is required!")
endif()

find_program(Ninja_EXECUTABLE ninja)
if(NOT Ninja_EXECUTABLE)
message(FATAL_ERROR "Cooking: Ninja is required!")
endif()

find_library(CGIF cgif PATHS "${EXT_INSTALL_DIR}/lib" NO_DEFAULT_PATH)
if (NOT CGIF)
ExternalProject_Add(cgif
URL "https://github.com/dloebl/cgif/archive/refs/tags/V${CGIF_VERSION}.tar.gz"
PREFIX "${CMAKE_CURRENT_BINARY_DIR}/cgif"
INSTALL_DIR ${EXT_INSTALL_DIR}
CONFIGURE_COMMAND
${Meson_EXECUTABLE} --prefix=<INSTALL_DIR> --libdir=lib <BINARY_DIR> <SOURCE_DIR>
BUILD_COMMAND
${Ninja_EXECUTABLE} -C <BINARY_DIR>
INSTALL_COMMAND
${Ninja_EXECUTABLE} -C <BINARY_DIR> install
)
else()
add_custom_target(cgif "")
endif()

find_library(LIBWEBP webp webpmux webpdemux PATHS "${EXT_INSTALL_DIR}/lib" NO_DEFAULT_PATH)
if(NOT LIBWEBP)
ExternalProject_Add(libwebp
Expand Down Expand Up @@ -304,13 +331,14 @@ if(NOT VIPS)
--with-tiff
--with-tiff-includes=${EXT_INSTALL_DIR}/include
--with-tiff-libraries=${EXT_INSTALL_DIR}/lib
--with-cgif
--without-magick
--without-orc
--without-gsf
--without-rsvg
${LIBSPNG_FLAGS}
${LIBHEIF_FLAGS}
DEPENDS libjpeg libpng libspng giflib libwebp libimagequant lcms2 libheif tiff
DEPENDS libjpeg libpng libspng giflib cgif libwebp libimagequant lcms2 libheif tiff
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I see that giflib is a decoder and cgif an encoder. I'd like to make sure that we can decode/encode/decode .gif files without any issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@warrenseine I've enabled GIFs in all of the tests, so I think they are confirming that?

BUILD_IN_SOURCE 1
)
else()
Expand Down
5 changes: 4 additions & 1 deletion lib/VERSIONS
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ SPNG_VERSION=0.6.0
# renovate: datasource=git-tags depName=giflib packageName=https://git.code.sf.net/p/giflib/code extractVersionTemplate=^(?<version>.*)$
GIF_VERSION=5.2.1

# renovate: datasource=github-releases depName=cgif packageName=dloebl/cgif extractVersionTemplate=^V(?<version>.*)$
CGIF_VERSION=0.3.0

# renovate: datasource=github-tags depName=libwebp packageName=webmproject/libwebp
WEBP_VERSION=1.1.0

Expand All @@ -32,4 +35,4 @@ LCMS2_VERSION=2.11
TIFF_VERSION=4.1.0

# renovate: datasource=github-releases depName=libvips packageName=libvips/libvips
VIPS_VERSION=8.12.2
VIPS_VERSION=8.13.0
5 changes: 4 additions & 1 deletion script/enum-generator/EnumGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from string import Template
from itertools import takewhile

DEFAULT_VIPS_VERSION = '8.12.2'
DEFAULT_VIPS_VERSION = '8.13.0'
JAVA_ENUM_TEMPLATE = "template/Enum.java"
C_ENUM_TEST_TEMPLATE = "template/VipsEnumTest.c"

Expand Down Expand Up @@ -90,6 +90,9 @@ def traverse_dictionary(dictionary, enum_output_dir, test_output_dir, license_co
'VIPS_OPERATION_SEQUENTIAL_UNBUFFERED': 2,
'VIPS_OPERATION_NOCACHE': 4,
'VIPS_OPERATION_DEPRECATED': 8,
'VIPS_OPERATION_UNTRUSTED': 16,
'VIPS_OPERATION_BLOCKED': 32,

'VIPS_FOREIGN_NONE': 0,
'VIPS_FOREIGN_PARTIAL': 1,
'VIPS_FOREIGN_BIGENDIAN': 2,
Expand Down
3 changes: 3 additions & 0 deletions script/enum-generator/template/VipsEnumTest.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,8 @@ assertEqualsNativeEnumValue(JNIEnv *env, const int expected, const char *classNa
JNIEXPORT void JNICALL
Java_com_criteo_vips_VipsEnumTest_TestNativeEnums(JNIEnv *env, jclass c)
{
if (VIPS_INIT("java") != 0) {
throwVipsException(env, "Unable to init vips");
}
$tests
}
8 changes: 7 additions & 1 deletion src/main/c/VipsContext.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,10 @@ JNIEXPORT void JNICALL
Java_com_criteo_vips_VipsContext_shutdown(__attribute__((unused)) JNIEnv *env, __attribute__((unused)) jobject obj)
{
vips_shutdown();
}
}

JNIEXPORT void JNICALL
Java_com_criteo_vips_VipsContext_setBlockUntrusted(__attribute__((unused))JNIEnv *env, __attribute__((unused)) jclass obj, jboolean enable)
{
vips_block_untrusted_set(enable);
}
8 changes: 8 additions & 0 deletions src/main/c/VipsContext.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions src/main/c/VipsImage.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,8 @@ Java_com_criteo_vips_VipsImage_writeToArrayNative(JNIEnv *env, jobject obj, jstr
status = vips_heifsave_buffer(im, &buffer, &result_length, "Q", quality, "compression", VIPS_FOREIGN_HEIF_COMPRESSION_AV1, NULL);
else
status = vips_heifsave_buffer(im, &buffer, &result_length, "compression", VIPS_FOREIGN_HEIF_COMPRESSION_AV1, NULL);
} else if (strcmp(ext, ".gif") == 0) {
status = vips_gifsave_buffer(im, &buffer, &result_length, "strip", strip, NULL);
} else {
if (quality < 0)
status = vips_image_write_to_buffer(im, ext, &buffer, &result_length, "strip", strip, NULL);
Expand All @@ -422,7 +424,7 @@ Java_com_criteo_vips_VipsImage_writeToArrayNative(JNIEnv *env, jobject obj, jstr
{
(*env)->ReleaseStringUTFChars(env, extension, ext);
throwVipsException(env, "Unable to write image buffer");
return ret;
return NULL;
}
ret = (*env)->NewByteArray(env, result_length);
(*env)->SetByteArrayRegion(env, ret, 0, result_length * sizeof (jbyte), buffer);
Expand Down Expand Up @@ -568,7 +570,7 @@ Java_com_criteo_vips_VipsImage_getPointPixelPacketNative(JNIEnv *env, jobject ob
{
throwVipsException(env, "Unable to get image point");
g_free(pixel);
return ret;
return NULL;
}
// Convert to uchar
for (int i = 0; i < result_length; ++i)
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/criteo/vips/Vips.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class Vips {
"png16",
"spng",
"gif",
"cgif",
"jpeg",
"turbojpeg",
"webp",
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/com/criteo/vips/VipsContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,11 @@ public class VipsContext extends Vips {
* Shutdown vips context
*/
public static native void shutdown();

/**
* Set whether or not to block untrusted operations from running.
* @param blockUntrusted
*/
public static native void setBlockUntrusted(boolean blockUntrusted);

}
6 changes: 5 additions & 1 deletion src/main/java/com/criteo/vips/enums/VipsOperationFlags.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ public enum VipsOperationFlags {
// must not be cached
Nocache(4),
// a compatibility thing
Deprecated(8);
Deprecated(8),
// not hardened for untrusted input
Untrusted(16),
// prevent this operation from running
Blocked(32);

private int value;
private static Map map = new HashMap<VipsOperationFlags, Integer>();
Expand Down
5 changes: 5 additions & 0 deletions src/test/c/VipsEnumTest.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ assertEqualsNativeEnumValue(JNIEnv *env, const int expected, const char *classNa
JNIEXPORT void JNICALL
Java_com_criteo_vips_VipsEnumTest_TestNativeEnums(JNIEnv *env, jclass c)
{
if (VIPS_INIT("java") != 0) {
throwVipsException(env, "Unable to init vips");
}
// VipsAccess
assertEqualsNativeEnumValue(env, VIPS_ACCESS_RANDOM, "com/criteo/vips/enums/VipsAccess", "Random");
assertEqualsNativeEnumValue(env, VIPS_ACCESS_SEQUENTIAL, "com/criteo/vips/enums/VipsAccess", "Sequential");
Expand Down Expand Up @@ -331,6 +334,8 @@ Java_com_criteo_vips_VipsEnumTest_TestNativeEnums(JNIEnv *env, jclass c)
assertEqualsNativeEnumValue(env, VIPS_OPERATION_SEQUENTIAL_UNBUFFERED, "com/criteo/vips/enums/VipsOperationFlags", "SequentialUnbuffered");
assertEqualsNativeEnumValue(env, VIPS_OPERATION_NOCACHE, "com/criteo/vips/enums/VipsOperationFlags", "Nocache");
assertEqualsNativeEnumValue(env, VIPS_OPERATION_DEPRECATED, "com/criteo/vips/enums/VipsOperationFlags", "Deprecated");
assertEqualsNativeEnumValue(env, VIPS_OPERATION_UNTRUSTED, "com/criteo/vips/enums/VipsOperationFlags", "Untrusted");
assertEqualsNativeEnumValue(env, VIPS_OPERATION_BLOCKED, "com/criteo/vips/enums/VipsOperationFlags", "Blocked");
// VipsOperationMath
assertEqualsNativeEnumValue(env, VIPS_OPERATION_MATH_SIN, "com/criteo/vips/enums/VipsOperationMath", "Sin");
assertEqualsNativeEnumValue(env, VIPS_OPERATION_MATH_COS, "com/criteo/vips/enums/VipsOperationMath", "Cos");
Expand Down
8 changes: 0 additions & 8 deletions src/test/java/com/criteo/vips/VipsImageTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ public void TestShouldOpenCorrectlyFromVipsImage(@FromDataPoints("filenames") St
public void TestWriteFromDirectByteBufferShouldNotThrows(@FromDataPoints("filenames") String filename,
VipsImageFormat output,
boolean strip) throws IOException, VipsException {
Assume.assumeTrue(output != VipsImageFormat.GIF);
Assume.assumeTrue(output != VipsImageFormat.AVIF);
ByteBuffer buffer = VipsTestUtils.getDirectByteBuffer(filename);
try (VipsImage img = new VipsImage(buffer, buffer.capacity())) {
Expand All @@ -164,7 +163,6 @@ public void TestWriteFromDirectByteBufferShouldNotThrows(@FromDataPoints("filena
public void TestWriteFromByteArrayShouldNotThrows(@FromDataPoints("filenames") String filename,
VipsImageFormat output,
boolean strip) throws IOException, VipsException {
Assume.assumeTrue(output != VipsImageFormat.GIF);
Assume.assumeTrue(output != VipsImageFormat.AVIF);
byte[] buffer = VipsTestUtils.getByteArray(filename);
try (VipsImage img = new VipsImage(buffer, buffer.length)) {
Expand Down Expand Up @@ -528,8 +526,6 @@ public void TestJpgShouldNotHasTransparency() throws IOException, VipsException

@Theory
public void TestShouldWriteToArrayHasCorrectHeaderSignature(String filename, VipsImageFormat vipsImageFormat) throws IOException, VipsException {
// libvips can't save into gif format
Assume.assumeTrue(vipsImageFormat != VipsImageFormat.GIF);
Assume.assumeTrue(vipsImageFormat != VipsImageFormat.AVIF);
ArrayList<Byte[]> expectedSignatures = SignaturesByExtension.get(vipsImageFormat.getFileExtension());
ByteBuffer buffer = VipsTestUtils.getDirectByteBuffer(filename);
Expand Down Expand Up @@ -574,8 +570,6 @@ public void TestShouldFindTrimWithTransparent() throws IOException, VipsExceptio

@Theory
public void TestSimplePipelineShouldNotThrow(String filename, VipsImageFormat vipsImageFormat) throws IOException, VipsException {
// libvips can't save into gif format
Assume.assumeTrue(vipsImageFormat != VipsImageFormat.GIF);
Assume.assumeTrue(vipsImageFormat != VipsImageFormat.AVIF);
ByteBuffer buffer = VipsTestUtils.getDirectByteBuffer(filename);
PixelPacket pixel = new PixelPacket(5.0, 255.0, 25.0);
Expand All @@ -595,8 +589,6 @@ public void TestSimplePipelineShouldNotThrow(String filename, VipsImageFormat vi

@Theory
public void TestShouldThrowAnExceptionOnCorruptedPng(VipsImageFormat vipsImageFormat) throws IOException, VipsException {
// libvips can't save into gif format
Assume.assumeTrue(vipsImageFormat != VipsImageFormat.GIF);
ByteBuffer buffer = VipsTestUtils.getDirectByteBuffer("olin.png");
try (VipsImage img = new VipsImage(buffer, buffer.capacity())) {
byte[] out = img.writeToArray(vipsImageFormat, JPGQuality, true);
Expand Down