From d2d1bd755db611230c68f52914251c07e865920d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Tue, 24 Nov 2020 01:54:35 +0100 Subject: [PATCH 1/8] Implement vips_tiffsave Upgrade jna, groovy and gradle --- build.gradle | 10 +- src/main/java/org/jlibvips/VipsAngle.java | 2 +- .../java/org/jlibvips/VipsForeignDzDepth.java | 11 + .../jlibvips/VipsForeignTiffCompression.java | 13 + .../jlibvips/VipsForeignTiffPredictor.java | 11 + .../org/jlibvips/VipsForeignTiffResunit.java | 10 + src/main/java/org/jlibvips/VipsImage.java | 15 + .../java/org/jlibvips/VipsRegionShrink.java | 14 + .../java/org/jlibvips/jna/VipsBindings.java | 1 + .../jlibvips/jna/VipsBindingsSingleton.java | 11 +- .../operations/TiffSaveOperation.java | 338 ++++++++++++++++++ src/test/groovy/org/jlibvips/Drawing.groovy | 4 +- 12 files changed, 431 insertions(+), 9 deletions(-) create mode 100644 src/main/java/org/jlibvips/VipsForeignDzDepth.java create mode 100644 src/main/java/org/jlibvips/VipsForeignTiffCompression.java create mode 100644 src/main/java/org/jlibvips/VipsForeignTiffPredictor.java create mode 100644 src/main/java/org/jlibvips/VipsForeignTiffResunit.java create mode 100644 src/main/java/org/jlibvips/VipsRegionShrink.java create mode 100644 src/main/java/org/jlibvips/operations/TiffSaveOperation.java diff --git a/build.gradle b/build.gradle index f1a9a86..db8be54 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ plugins { group 'io.github.codecitizen' archivesBaseName = 'jlibvips' -version '1.3.0.RELEASE' +version '1.4.0-SNAPSHOT' sourceCompatibility = 1.8 targetCompatibility = 1.8 @@ -25,10 +25,10 @@ repositories { } dependencies { - implementation group: 'net.java.dev.jna', name: 'jna', version: '5.1.0' - implementation 'org.codehaus.groovy:groovy:2.5.4' + implementation group: 'net.java.dev.jna', name: 'jna', version: '5.6.0' + implementation 'org.codehaus.groovy:groovy:2.5.13' - testCompile 'org.spockframework:spock-core:1.2-groovy-2.5' + testCompile 'org.spockframework:spock-core:1.3-groovy-2.5' } jar { @@ -57,7 +57,7 @@ javadoc { } wrapper { - gradleVersion = '5.0' + gradleVersion = '6.7.1' } artifacts { diff --git a/src/main/java/org/jlibvips/VipsAngle.java b/src/main/java/org/jlibvips/VipsAngle.java index e4b8995..be4dce1 100644 --- a/src/main/java/org/jlibvips/VipsAngle.java +++ b/src/main/java/org/jlibvips/VipsAngle.java @@ -26,7 +26,7 @@ public static VipsAngle fromInteger(int value) { case 180: return D180; case 270: return D270; default: - throw new IllegalArgumentException("Allowed VipsAngle's are [0°, 90°, 180°, 270°]."); + throw new IllegalArgumentException("Allowed VipsAngle's are [0, 90, 180, 270]."); } } diff --git a/src/main/java/org/jlibvips/VipsForeignDzDepth.java b/src/main/java/org/jlibvips/VipsForeignDzDepth.java new file mode 100644 index 0000000..ac58227 --- /dev/null +++ b/src/main/java/org/jlibvips/VipsForeignDzDepth.java @@ -0,0 +1,11 @@ +package org.jlibvips; + +/** + * https://libvips.github.io/libvips/API/current/VipsForeignSave.html#VipsForeignDzDepth + */ +public enum VipsForeignDzDepth { + VIPS_FOREIGN_DZ_DEPTH_ONEPIXEL, + VIPS_FOREIGN_DZ_DEPTH_ONETILE, + VIPS_FOREIGN_DZ_DEPTH_ONE, + VIPS_FOREIGN_DZ_DEPTH_LAST +} diff --git a/src/main/java/org/jlibvips/VipsForeignTiffCompression.java b/src/main/java/org/jlibvips/VipsForeignTiffCompression.java new file mode 100644 index 0000000..8dfaef5 --- /dev/null +++ b/src/main/java/org/jlibvips/VipsForeignTiffCompression.java @@ -0,0 +1,13 @@ +package org.jlibvips; + +public enum VipsForeignTiffCompression { + VIPS_FOREIGN_TIFF_COMPRESSION_NONE, + VIPS_FOREIGN_TIFF_COMPRESSION_JPEG, + VIPS_FOREIGN_TIFF_COMPRESSION_DEFLATE, + VIPS_FOREIGN_TIFF_COMPRESSION_PACKBITS, + VIPS_FOREIGN_TIFF_COMPRESSION_CCITTFAX4, + VIPS_FOREIGN_TIFF_COMPRESSION_LZW, + VIPS_FOREIGN_TIFF_COMPRESSION_WEBP, + VIPS_FOREIGN_TIFF_COMPRESSION_ZSTD, + VIPS_FOREIGN_TIFF_COMPRESSION_LAST +} diff --git a/src/main/java/org/jlibvips/VipsForeignTiffPredictor.java b/src/main/java/org/jlibvips/VipsForeignTiffPredictor.java new file mode 100644 index 0000000..1dca832 --- /dev/null +++ b/src/main/java/org/jlibvips/VipsForeignTiffPredictor.java @@ -0,0 +1,11 @@ +package org.jlibvips; + +/** + * https://libvips.github.io/libvips/API/current/VipsForeignSave.html#VipsForeignTiffPredictor + */ +public enum VipsForeignTiffPredictor { + VIPS_FOREIGN_TIFF_PREDICTOR_NONE, + VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL, + VIPS_FOREIGN_TIFF_PREDICTOR_FLOAT, + VIPS_FOREIGN_TIFF_PREDICTOR_LAST +} diff --git a/src/main/java/org/jlibvips/VipsForeignTiffResunit.java b/src/main/java/org/jlibvips/VipsForeignTiffResunit.java new file mode 100644 index 0000000..c89edab --- /dev/null +++ b/src/main/java/org/jlibvips/VipsForeignTiffResunit.java @@ -0,0 +1,10 @@ +package org.jlibvips; + +/** + * https://libvips.github.io/libvips/API/current/VipsForeignSave.html#VipsForeignTiffResunit + */ +public enum VipsForeignTiffResunit { + VIPS_FOREIGN_TIFF_RESUNIT_CM, + VIPS_FOREIGN_TIFF_RESUNIT_INCH, + VIPS_FOREIGN_TIFF_RESUNIT_LAST +} diff --git a/src/main/java/org/jlibvips/VipsImage.java b/src/main/java/org/jlibvips/VipsImage.java index c522c85..e3d25bd 100644 --- a/src/main/java/org/jlibvips/VipsImage.java +++ b/src/main/java/org/jlibvips/VipsImage.java @@ -388,6 +388,21 @@ public PngSaveOperation png() { return new PngSaveOperation(this); } + /** + * Write an image to a file in TIFF format. + * + * + * java.nio.Path path = image.tiff().save(); + * + * + * vips_tiffsave() + * + * @return the {@link TiffSaveOperation} + */ + public TiffSaveOperation tiff() { + return new TiffSaveOperation(this); + } + /** * Get the width of this image. * diff --git a/src/main/java/org/jlibvips/VipsRegionShrink.java b/src/main/java/org/jlibvips/VipsRegionShrink.java new file mode 100644 index 0000000..d670cb0 --- /dev/null +++ b/src/main/java/org/jlibvips/VipsRegionShrink.java @@ -0,0 +1,14 @@ +package org.jlibvips; + +/** + * https://libvips.github.io/libvips/API/current/VipsRegion.html#VipsRegionShrink + */ +public enum VipsRegionShrink { + VIPS_REGION_SHRINK_MEAN, + VIPS_REGION_SHRINK_MEDIAN, + VIPS_REGION_SHRINK_MODE, + VIPS_REGION_SHRINK_MAX, + VIPS_REGION_SHRINK_MIN, + VIPS_REGION_SHRINK_NEAREST, + VIPS_REGION_SHRINK_LAST +} diff --git a/src/main/java/org/jlibvips/jna/VipsBindings.java b/src/main/java/org/jlibvips/jna/VipsBindings.java index 8a05cd6..69455dc 100644 --- a/src/main/java/org/jlibvips/jna/VipsBindings.java +++ b/src/main/java/org/jlibvips/jna/VipsBindings.java @@ -25,6 +25,7 @@ public interface VipsBindings extends Library { int vips_jpegsave(Pointer in, String filename, Object...args); int vips_webpsave(Pointer in, String filename, Object...args); int vips_pngsave(Pointer in, String filename, Object...args); + int vips_tiffsave(Pointer in, String filename, Object...args); int vips_insert(Pointer main, Pointer sub, Pointer[] out, int x, int y, Object...args); int vips_join(Pointer in1, Pointer in2, Pointer[] out, int direction, Object...args); diff --git a/src/main/java/org/jlibvips/jna/VipsBindingsSingleton.java b/src/main/java/org/jlibvips/jna/VipsBindingsSingleton.java index b3cd256..49ec8aa 100644 --- a/src/main/java/org/jlibvips/jna/VipsBindingsSingleton.java +++ b/src/main/java/org/jlibvips/jna/VipsBindingsSingleton.java @@ -18,11 +18,20 @@ public static VipsBindings instance() { if(libraryPath == null || libraryPath.isEmpty()) { throw new IllegalStateException("Please call VipsBindingsSingleton.configure(...) before getting the instance."); } - INSTANCE = Native.load(libraryPath, VipsBindings.class); + try { + INSTANCE = Native.load(libraryPath, VipsBindings.class); + } catch (UnsatisfiedLinkError e) { + libraryPath = guessPath(); + INSTANCE = Native.load(libraryPath, VipsBindings.class); + } } return INSTANCE; } + private static String guessPath() { + return "/usr/local/Cellar/vips/8.10.2_4/lib/libvips.dylib"; + } + private VipsBindingsSingleton() { } diff --git a/src/main/java/org/jlibvips/operations/TiffSaveOperation.java b/src/main/java/org/jlibvips/operations/TiffSaveOperation.java new file mode 100644 index 0000000..3c132fe --- /dev/null +++ b/src/main/java/org/jlibvips/operations/TiffSaveOperation.java @@ -0,0 +1,338 @@ +package org.jlibvips.operations; + +import org.jlibvips.*; +import org.jlibvips.exceptions.VipsException; +import org.jlibvips.jna.VipsBindingsSingleton; +import org.jlibvips.util.Varargs; +import org.jlibvips.util.VipsUtils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * Write a VIPS image to a file as TIFF. + */ +public class TiffSaveOperation implements SaveOperation { + + private final VipsImage image; + + private Integer quality; + private VipsForeignTiffCompression tiffCompression; + private Boolean tile; + private Integer tileWidth; + private Integer tileHeight; + private Boolean pyramid; + private VipsForeignTiffPredictor predictor; + private String profile; + private Integer bitdepth; + private Boolean miniswhite; + private VipsForeignTiffResunit resunit; + private Double xres; + private Double yres; + private Boolean bigtiff; + private Boolean properties; + private VipsRegionShrink region_shrink; + private VipsForeignDzDepth depth; + private Integer level; + private Boolean lossless; + private Boolean subifd; + + public TiffSaveOperation(VipsImage image) { + this.image = image; + } + + @Override + public Path save() throws IOException, VipsException { + if (tileWidth % 128 != 0 || tileHeight % 128 != 0) { + throw new VipsException("Wrong value for tileWidth or TileHeight", 1); + } + Path path = Files.createTempFile("jlibvips", ".tif"); + int ret = VipsBindingsSingleton.instance().vips_tiffsave(image.getPtr(), path.toString(), + new Varargs().add("Q", quality) + .add("compression", VipsUtils.toOrdinal(tiffCompression)) + .add("tile", VipsUtils.booleanToInteger(tile)) + .add("tile_width", tileWidth) + .add("tile_height", tileHeight) + .add("pyramid", VipsUtils.booleanToInteger(pyramid)) + .add("predictor", VipsUtils.toOrdinal(predictor)) + .add("profile", profile) + .add("bitdepth", bitdepth) + .add("miniswhite", miniswhite) + .add("resunit", VipsUtils.toOrdinal(resunit)) + .add("xres", xres) + .add("yres", yres) + .add("bigtiff", bigtiff) + .add("properties", properties) + .add("region_shrink", region_shrink) + .add("depth", depth) + .add("level", level) + .add("lossless", lossless) + .add("subifd", subifd) + .toArray()); + if (ret != 0) { + throw new VipsException("vips_tiffsave", ret); + } + return path; + } + + /** + * Set the JPEG compression factor. Default 75. + * + * @param q quality factor + * @return this + */ + public TiffSaveOperation quality(Integer q) { + this.quality = q; + return this; + } + + /** + * Use compression to set the tiff compression. Currently jpeg, packbits, fax4, + * lzw, none, deflate, webp and zstd are supported. The default is no compression. + * JPEG compression is a good lossy compressor for photographs, packbits is good + * for 1-bit images, and deflate is the best lossless compression TIFF can do. + * + * @param compression compression ENUM + * @return this + */ + public TiffSaveOperation compression(VipsForeignTiffCompression compression) { + this.tiffCompression = compression; + return this; + } + + /** + * Set true to write a tiled tiff + * + * @param tile true or false + * @return this + */ + public TiffSaveOperation tile(boolean tile) { + this.tile = tile; + return this; + } + + /** + * Set tile width, must be 2^N, i.e. 128, 256, 512 etc + * Default is 128. + * + * @param tileWidth width of tiles + * @return this + */ + public TiffSaveOperation tileWidth(int tileWidth) { + this.tileWidth = tileWidth; + return this; + } + + /** + * Set tile width, must be 2^N, i.e. 128, 256, 512 etc + * Default is 128. + * + * @param tileHeight height of tiles + * @return this + */ + public TiffSaveOperation tileHeight(int tileHeight) { + this.tileHeight = tileHeight; + return this; + } + + /** + * Set pyramid to write the image as a set of images, one per page, of decreasing size. + * By default, the pyramid stops when the image is small enough to fit in one tile. + * Use depth to stop when the image fits in one pixel, or to only write a single layer. + * + * @param pyramid true or false + * @return this + */ + public TiffSaveOperation pyramid(boolean pyramid) { + this.pyramid = pyramid; + return this; + } + + /** + * Use predictor to set the predictor for lzw and deflate compression. + * It defaults to VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL, meaning horizontal + * differencing. Please refer to the libtiff specifications for further + * discussion of various predictors. + * + * @param predictor enum + * @return this + */ + public TiffSaveOperation predictor(VipsForeignTiffPredictor predictor) { + this.predictor = predictor; + return this; + } + + /** + * Use profile to give the filename of a profile to be embedded in the TIFF. + * This does not affect the pixels which are written, just the way they are tagged. + * See vips_profile_load() for details on profile naming. + *

+ * If no profile is specified and the VIPS header contains an ICC profile named + * VIPS_META_ICC_NAME, the profile from the VIPS header will be attached. + * + * @param profile name of profile + * @return this + */ + public TiffSaveOperation profile(String profile) { + this.profile = profile; + return this; + } + + /** + * Set bitdepth to save 8-bit uchar images as 1, 2 or 4-bit TIFFs. In case of + * depth 1: Values >128 are written as white, values <=128 as black. Normally + * vips will write MINISBLACK TIFFs where black is a 0 bit, but if you set + * miniswhite, it will use 0 for a white bit. Many pre-press applications + * only work with images which use this sense. miniswhite only affects one-bit images, + * it does nothing for greyscale images. In case of depth 2: The same holds + * but values < 64 are written as black. For 64 <= values < 128 they are written + * as dark grey, for 128 <= values < 192 they are written as light gray and values + * above are written as white. In case miniswhite is set to true this behavior is + * inverted. In case of depth 4: values < 16 are written as black, and so on for + * the lighter shades. In case miniswhite is set to true this behavior is inverted. + * + * @param bitdepth the bit depth + * @return this + */ + public TiffSaveOperation bitdepth(Integer bitdepth) { + this.bitdepth = bitdepth; + return this; + } + + /** + * Normally vips will write MINISBLACK TIFFs where black is a 0 bit, but if you set + * miniswhite , it will use 0 for a white bit. Many pre-press applications only work + * with images which use this sense. miniswhite only affects one-bit images, it does + * nothing for greyscale images. + * + * @param miniswhite true or false + * @return this + */ + public TiffSaveOperation miniswhite(boolean miniswhite) { + this.miniswhite = miniswhite; + return this; + } + + /** + * Use xres and yres to override the default horizontal and vertical resolutions. + * By default these values are taken from the VIPS image header. libvips resolution + * is always in pixels per millimetre. + * + * @param xres horizontal resolution in pixels/mm + * @return this + */ + public TiffSaveOperation xres(Double xres) { + this.xres = xres; + return this; + } + + /** + * Use xres and yres to override the default horizontal and vertical resolutions. + * By default these values are taken from the VIPS image header. libvips resolution + * is always in pixels per millimetre. + * + * @param yres horizontal resolution in pixels/mm + * @return this + */ + public TiffSaveOperation yres(Double yres) { + this.yres = yres; + return this; + } + + /** + * Set bigtiff to attempt to write a bigtiff. Bigtiff is a variant of the + * TIFF format that allows more than 4GB in a file. + * + * @param bigtiff true or false + * @return this + */ + public TiffSaveOperation bigtiff(boolean bigtiff) { + this.bigtiff = bigtiff; + return this; + } + + /** + * Set properties to write all vips metadata to the IMAGEDESCRIPTION tag as xml. + * If properties is not set, the value of VIPS_META_IMAGEDESCRIPTION is used instead. + * + * @param properties set TRUE to write an IMAGEDESCRIPTION tag + * @return this + */ + public TiffSaveOperation properties(boolean properties) { + this.properties = properties; + return this; + } + + /** + * Use region_shrink to set how images will be shrunk when generating pyramid: + * by default each 2x2 block is just averaged, but you can set MODE or MEDIAN as well. + * + * @param region_shrink How to shrink each 2x2 region. + * @return this + */ + public TiffSaveOperation region_shrink(VipsRegionShrink region_shrink) { + this.region_shrink = region_shrink; + return this; + } + + /** + * By default, the pyramid stops when the image is small enough to fit in one tile. + * Use depth to stop when the image fits in one pixel, or to only write a single layer. + * + * @param depth how deep to make the pyramid + * @return this + */ + public TiffSaveOperation depth(VipsForeignDzDepth depth) { + this.depth = depth; + return this; + } + + /** + * Use level to set the ZSTD compression level. + * + * @param level Zstd compression level + * @return this + */ + public TiffSaveOperation level(Integer level) { + this.level = level; + return this; + } + + /** + * Use lossless to set WEBP lossless mode on + * + * @param lossless WebP losssless mode + * @return this + */ + public TiffSaveOperation lossless(boolean lossless) { + this.lossless = lossless; + return this; + } + + /** + * Set subifd to save pyramid layers as sub-directories of the main image. + * Setting this option can improve compatibility with formats like OME. + * + * @param subifd set TRUE to write pyr layers as sub-ifds + * @return this + */ + public TiffSaveOperation subifd(boolean subifd) { + this.subifd = subifd; + return this; + } + + /** + * Use resunit to override the default resolution unit. + * The default resolution unit is taken from the header field + * VIPS_META_RESOLUTION_UNIT. If this field is not set, then + * VIPS defaults to cm. + * + * @param resunit set resolution unit + * @return this + */ + public TiffSaveOperation resunit(VipsForeignTiffResunit resunit) { + this.resunit = resunit; + return this; + } +} diff --git a/src/test/groovy/org/jlibvips/Drawing.groovy b/src/test/groovy/org/jlibvips/Drawing.groovy index 924f100..c474ff6 100644 --- a/src/test/groovy/org/jlibvips/Drawing.groovy +++ b/src/test/groovy/org/jlibvips/Drawing.groovy @@ -4,7 +4,6 @@ package org.jlibvips import spock.lang.Specification import java.nio.file.Files -import java.nio.file.Paths import java.nio.file.StandardCopyOption import static org.jlibvips.TestUtils.copyResourceToFS @@ -65,6 +64,7 @@ class Drawing extends Specification { def image = VipsImage.fromFile imagePath def whiteRgb = color(255, 255, 255) def transparent = color(0, 0, 0, 0) + def dir = Files.createTempDirectory("tint") when: def lut = VipsImage.identity().create() lut = lut.moreEq(200).ifthenelse(lut.newFromImage(transparent), lut.newFromImage(tint)) @@ -77,7 +77,7 @@ class Drawing extends Specification { then: tinted != null println tinted - def dest = Paths.get("/Volumes/HD/backups/images/${colorName}.png") + def dest = dir.resolve( "${colorName}.png") Files.move(tinted.png().save(), dest, StandardCopyOption.REPLACE_EXISTING) cleanup: Files.deleteIfExists imagePath From 396c8b9adf667ea048a35f24a7d5baea583e4889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Tue, 24 Nov 2020 02:10:25 +0100 Subject: [PATCH 2/8] Update README with latest version, and example for TIFF save --- README.md | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9daa559..a7fee68 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,12 @@ A Java interface to [llibvips](http://libvips.github.io/libvips/), the fast imag io.github.codecitizen jlibvips - 1.2.1 + 1.3.0.RELEASE ``` ```groovy -implementation 'io.github.codecitizen:jlibvips:1.2.1' +implementation 'io.github.codecitizen:jlibvips:1.3.0.RELEASE' ``` **Configure Path to libvips Library:** @@ -22,6 +22,12 @@ implementation 'io.github.codecitizen:jlibvips:1.2.1' VipsBindingsSingleton.configure("/usr/local/lib/libvips.so"); ``` +On MacOS you can install `brew install vips` and refer to something like: + +```java +VipsBindingsSingleton.configure("/usr/local/Cellar/glib/2.66.2_1/lib/libglib-2.0.0.dylib"); +``` + **Example: Generate a Thumbnail for a PDF.** ```java @@ -52,7 +58,7 @@ public class PDFThumbnailExample { } ``` -**Example: Create an Image Pyramid form a large PNG File.** +**Example: Create a DZ Image Pyramid from a large PNG File.** ```java @@ -64,7 +70,7 @@ import java.nio.file.Paths; public class ImagePyramidExample { public static void main(String[] args) { - var image = VipsImage.formFile(Paths.get(args[0])); + var image = VipsImage.fromFile(Paths.get(args[0])); var directory = Files.createTempDirectory("example-pyramid"); image.deepZoom(directory) .layout(DeepZoomLayouts.Google) @@ -72,7 +78,36 @@ public class ImagePyramidExample { .suffix(".jpg[Q=100]") .save(); image.unref(); - System.out.printf("Pyramid generated in folder '%s'.%n", directory.toString()); + System.out.printf("Pyramid generated in folder '%s'.\n", directory.toString()); + System.out.println("Done."); + } + +} +``` + +**Example: Create a TIFF Image Pyramid from a large PNG File.** + +```java +package jlibvips.example; + +import org.jlibvips.VipsImage; +import java.nio.file.Paths; + +public class ImagePyramidExample { + + public static void main(String[] args) { + var image = VipsImage.fromFile(Paths.get(args[0])); + Path dest = image + .tiff() + .tile(true) + .tileHeight(256) + .tileWidth(256) + .compression(VipsForeignTiffCompression.VIPS_FOREIGN_TIFF_COMPRESSION_JPEG) + .quality(80) + .pyramid(true) + .save(); + image.unref(); + System.out.printf("Pyramid generated in file '%s'.\n", dest.toString()); System.out.println("Done."); } From 28fd503ae7b0909a56ea71f677691cb8d95ceb25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Tue, 24 Nov 2020 09:32:50 +0100 Subject: [PATCH 3/8] Wrap types for remaining variables --- .../org/jlibvips/operations/TiffSaveOperation.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jlibvips/operations/TiffSaveOperation.java b/src/main/java/org/jlibvips/operations/TiffSaveOperation.java index 3c132fe..6031741 100644 --- a/src/main/java/org/jlibvips/operations/TiffSaveOperation.java +++ b/src/main/java/org/jlibvips/operations/TiffSaveOperation.java @@ -58,17 +58,17 @@ public Path save() throws IOException, VipsException { .add("predictor", VipsUtils.toOrdinal(predictor)) .add("profile", profile) .add("bitdepth", bitdepth) - .add("miniswhite", miniswhite) + .add("miniswhite", VipsUtils.booleanToInteger(miniswhite)) .add("resunit", VipsUtils.toOrdinal(resunit)) .add("xres", xres) .add("yres", yres) - .add("bigtiff", bigtiff) - .add("properties", properties) - .add("region_shrink", region_shrink) - .add("depth", depth) + .add("bigtiff", VipsUtils.booleanToInteger(bigtiff)) + .add("properties", VipsUtils.booleanToInteger(properties)) + .add("region_shrink", VipsUtils.toOrdinal(region_shrink)) + .add("depth", VipsUtils.toOrdinal(depth)) .add("level", level) - .add("lossless", lossless) - .add("subifd", subifd) + .add("lossless", VipsUtils.booleanToInteger(lossless)) + .add("subifd", VipsUtils.booleanToInteger(subifd)) .toArray()); if (ret != 0) { throw new VipsException("vips_tiffsave", ret); From 3adc0c717cccd35cadb7cf491e7c31c9990862e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Tue, 24 Nov 2020 10:02:57 +0100 Subject: [PATCH 4/8] Env variables JLIBVIPS_LIB_PATH and ENV_GLIBC_PATH to easily configure library paths on different systems --- README.md | 11 +++++--- .../jlibvips/jna/VipsBindingsSingleton.java | 13 +++------ .../jna/glib/GLibBindingsSingleton.java | 27 ++++++++++--------- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index a7fee68..42de00e 100644 --- a/README.md +++ b/README.md @@ -18,14 +18,15 @@ implementation 'io.github.codecitizen:jlibvips:1.3.0.RELEASE' **Configure Path to libvips Library:** +From code: ```java VipsBindingsSingleton.configure("/usr/local/lib/libvips.so"); ``` -On MacOS you can install `brew install vips` and refer to something like: - -```java -VipsBindingsSingleton.configure("/usr/local/Cellar/glib/2.66.2_1/lib/libglib-2.0.0.dylib"); +You may also set the lib path in environment variable `JLIBVIPS_LIB_PATH`, which is useful +when running your app in multiple environments where lib position changes. Example for macOS: +```shell script +export JLIBVIPS_LIB_PATH="/usr/local/Cellar/vips/8.10.2_4/lib/libvips.dylib" ``` **Example: Generate a Thumbnail for a PDF.** @@ -169,3 +170,5 @@ VIPS[G_LOG_LEVEL_INFO]: gaussblur mask width 17 VIPS[G_LOG_LEVEL_INFO]: convi: using C path VIPS[G_LOG_LEVEL_INFO]: convi: using C path ``` + +The GLIBC lib path can also be set using env variable `JLIBVIPS_GLIBC_PATH`. \ No newline at end of file diff --git a/src/main/java/org/jlibvips/jna/VipsBindingsSingleton.java b/src/main/java/org/jlibvips/jna/VipsBindingsSingleton.java index 49ec8aa..b896623 100644 --- a/src/main/java/org/jlibvips/jna/VipsBindingsSingleton.java +++ b/src/main/java/org/jlibvips/jna/VipsBindingsSingleton.java @@ -4,8 +4,8 @@ public class VipsBindingsSingleton { - - private static String libraryPath = "vips"; + private static final String ENV_LIB_PATH = "JLIBVIPS_LIB_PATH"; + private static String libraryPath = System.getenv(ENV_LIB_PATH) == null ? "vips" : System.getenv(ENV_LIB_PATH); public static void configure(String lp) { libraryPath = lp; @@ -16,22 +16,17 @@ public static void configure(String lp) { public static VipsBindings instance() { if(INSTANCE == null) { if(libraryPath == null || libraryPath.isEmpty()) { - throw new IllegalStateException("Please call VipsBindingsSingleton.configure(...) before getting the instance."); + throw new IllegalStateException("Please call VipsBindingsSingleton.configure(...) or set env var JLIBVIPS_LIB_PATH before getting the instance."); } try { INSTANCE = Native.load(libraryPath, VipsBindings.class); } catch (UnsatisfiedLinkError e) { - libraryPath = guessPath(); - INSTANCE = Native.load(libraryPath, VipsBindings.class); + throw new IllegalStateException("Please call VipsBindingsSingleton.configure(...) or set env var JLIBVIPS_LIB_PATH before getting the instance."); } } return INSTANCE; } - private static String guessPath() { - return "/usr/local/Cellar/vips/8.10.2_4/lib/libvips.dylib"; - } - private VipsBindingsSingleton() { } diff --git a/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java b/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java index d955916..2e03896 100644 --- a/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java +++ b/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java @@ -4,22 +4,25 @@ public class GLibBindingsSingleton { - private static String libraryPath = "/usr/local/opt/glib/lib/libglib-2.0.dylib"; + private static final String ENV_GLIBC_PATH = "JLIBVIPS_GLIBC_PATH"; + private static String libraryPath = System.getenv(ENV_GLIBC_PATH) == null + ? "/usr/local/opt/glib/lib/libglib-2.0.dylib" + : System.getenv(ENV_GLIBC_PATH); - public static void configure(String lp) { - libraryPath = lp; - } + public static void configure(String lp) { + libraryPath = lp; + } - private static GLibBindings INSTANCE; + private static GLibBindings INSTANCE; - public static GLibBindings instance() { - if(INSTANCE == null) { - INSTANCE = Native.load(libraryPath, GLibBindings.class); + public static GLibBindings instance() { + if(INSTANCE == null) { + INSTANCE = Native.load(libraryPath, GLibBindings.class); + } + return INSTANCE; } - return INSTANCE; - } - private GLibBindingsSingleton() { - } + private GLibBindingsSingleton() { + } } From 5edb404f94143d39544d125b2431adab01c7ffcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Wed, 25 Nov 2020 10:54:01 +0100 Subject: [PATCH 5/8] Change default lib path to glibc on linux (tested in ubuntu docker image) --- src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java b/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java index 2e03896..f58b60a 100644 --- a/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java +++ b/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java @@ -6,7 +6,7 @@ public class GLibBindingsSingleton { private static final String ENV_GLIBC_PATH = "JLIBVIPS_GLIBC_PATH"; private static String libraryPath = System.getenv(ENV_GLIBC_PATH) == null - ? "/usr/local/opt/glib/lib/libglib-2.0.dylib" + ? "libglib-2.0" : System.getenv(ENV_GLIBC_PATH); public static void configure(String lp) { From 6fe772fe828ba4125925211b9b88770e926e8ba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Wed, 25 Nov 2020 10:56:12 +0100 Subject: [PATCH 6/8] Undo whitespace changes --- .../jna/glib/GLibBindingsSingleton.java | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java b/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java index f58b60a..b9b900b 100644 --- a/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java +++ b/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java @@ -4,25 +4,25 @@ public class GLibBindingsSingleton { - private static final String ENV_GLIBC_PATH = "JLIBVIPS_GLIBC_PATH"; - private static String libraryPath = System.getenv(ENV_GLIBC_PATH) == null - ? "libglib-2.0" - : System.getenv(ENV_GLIBC_PATH); - - public static void configure(String lp) { - libraryPath = lp; - } - - private static GLibBindings INSTANCE; - - public static GLibBindings instance() { - if(INSTANCE == null) { - INSTANCE = Native.load(libraryPath, GLibBindings.class); - } - return INSTANCE; - } - - private GLibBindingsSingleton() { - } + private static final String ENV_GLIBC_PATH = "JLIBVIPS_GLIBC_PATH"; + private static String libraryPath = System.getenv(ENV_GLIBC_PATH) == null + ? "libglib-2.0" + : System.getenv(ENV_GLIBC_PATH); + + public static void configure(String lp) { + libraryPath = lp; + } + + private static GLibBindings INSTANCE; + + public static GLibBindings instance() { + if(INSTANCE == null) { + INSTANCE = Native.load(libraryPath, GLibBindings.class); + } + return INSTANCE; + } + + private GLibBindingsSingleton() { + } } From 275a7ba8ab9924b03798981ccf4d87fcc2f3cabd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Wed, 25 Nov 2020 10:57:01 +0100 Subject: [PATCH 7/8] Undo whitespace changes --- .../org/jlibvips/jna/glib/GLibBindingsSingleton.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java b/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java index b9b900b..2be624f 100644 --- a/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java +++ b/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java @@ -10,16 +10,16 @@ public class GLibBindingsSingleton { : System.getenv(ENV_GLIBC_PATH); public static void configure(String lp) { - libraryPath = lp; + libraryPath = lp; } private static GLibBindings INSTANCE; public static GLibBindings instance() { - if(INSTANCE == null) { - INSTANCE = Native.load(libraryPath, GLibBindings.class); - } - return INSTANCE; + if(INSTANCE == null) { + INSTANCE = Native.load(libraryPath, GLibBindings.class); + } + return INSTANCE; } private GLibBindingsSingleton() { From 811ce624947bf13e2ea8728938b3b82d22591035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Wed, 25 Nov 2020 10:57:25 +0100 Subject: [PATCH 8/8] Undo whitespace changes --- .../java/org/jlibvips/jna/glib/GLibBindingsSingleton.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java b/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java index 2be624f..839ce52 100644 --- a/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java +++ b/src/main/java/org/jlibvips/jna/glib/GLibBindingsSingleton.java @@ -6,8 +6,8 @@ public class GLibBindingsSingleton { private static final String ENV_GLIBC_PATH = "JLIBVIPS_GLIBC_PATH"; private static String libraryPath = System.getenv(ENV_GLIBC_PATH) == null - ? "libglib-2.0" - : System.getenv(ENV_GLIBC_PATH); + ? "libglib-2.0" + : System.getenv(ENV_GLIBC_PATH); public static void configure(String lp) { libraryPath = lp;