Skip to content

Commit a2019bd

Browse files
authored
Add support for multi-output operations (#163)
1 parent b355fc7 commit a2019bd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2979
-1120
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[submodule "libvips"]
22
path = libvips
33
url = https://github.com/libvips/libvips/
4-
branch = tags/v8.17.0
4+
branch = tags/v8.17.1

README.md

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

2525
dependencies {
26-
implementation("app.photofox.vips-ffm:vips-ffm-core:1.7.1")
26+
implementation("app.photofox.vips-ffm:vips-ffm-core:1.8.0")
2727
}
2828
```
2929

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

Lines changed: 201 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
import app.photofox.vipsffm.enums.VipsDirection;
1414
import app.photofox.vipsffm.enums.VipsExtend;
1515
import app.photofox.vipsffm.enums.VipsFailOn;
16+
import app.photofox.vipsffm.enums.VipsForeignDzContainer;
1617
import app.photofox.vipsffm.enums.VipsForeignDzDepth;
18+
import app.photofox.vipsffm.enums.VipsForeignDzLayout;
1719
import app.photofox.vipsffm.enums.VipsForeignHeifCompression;
1820
import app.photofox.vipsffm.enums.VipsForeignHeifEncoder;
1921
import app.photofox.vipsffm.enums.VipsForeignPpmFormat;
@@ -1974,6 +1976,184 @@ public void drawSmudge(int left, int top, int width, int height, VipsOption... a
19741976
VipsInvoker.invokeOperation(arena, "draw_smudge", callArgs);
19751977
}
19761978

1979+
/// Save an image as a set of tiles at various resolutions. By default dzsave
1980+
/// uses DeepZoom layout -- use `layout` to pick other conventions.
1981+
///
1982+
/// [VImage#dzsave] creates a directory called `name` to hold the tiles.
1983+
/// If `name` ends `.zip`, [VImage#dzsave] will create a zip file called
1984+
/// `name` to hold the tiles. You can use `container` to force zip file output.
1985+
///
1986+
/// Use `basename` to set the name of the image we are creating. The
1987+
/// default value is set from `name`.
1988+
///
1989+
/// By default, tiles are written as JPEGs. Use `Q` set set the JPEG quality
1990+
/// factor.
1991+
///
1992+
/// You can set `suffix` to something like `".png[bitdepth=4]"` to write tiles
1993+
/// in another format.
1994+
///
1995+
/// In Google layout mode, edge tiles are expanded to `tile_size` by `tile_size`
1996+
/// pixels. Normally they are filled with white, but you can set another colour
1997+
/// with `background`. Images are usually placed at the top-left of the tile,
1998+
/// but you can have them centred by turning on `centre`.
1999+
///
2000+
/// You can set the size and overlap of tiles with `tile_size` and `overlap`.
2001+
/// They default to the correct settings for the selected `layout`. The deepzoom
2002+
/// defaults produce 256x256 jpeg files for centre tiles, the most efficient
2003+
/// size.
2004+
///
2005+
/// Use `depth` to control how low the pyramid goes. This defaults to the
2006+
/// correct setting for the `layout` you select.
2007+
///
2008+
/// You can rotate the image during write with the `angle` argument. However,
2009+
/// this will only work for images which support random access, like openslide,
2010+
/// and not for things like JPEG. You'll need to rotate those images
2011+
/// yourself with [VImage#rot]. Note that the `autorotate` option to the loader
2012+
/// may do what you need.
2013+
///
2014+
/// By default, all tiles are stripped since usually you do not want a copy of
2015+
/// all metadata in every tile. Set `keep` if you want to keep metadata.
2016+
///
2017+
/// If `container` is set to `zip`, you can set a compression level from -1
2018+
/// (use zlib default), 0 (store, compression disabled) to 9 (max compression).
2019+
/// If no value is given, the default is to store files without compression.
2020+
///
2021+
/// You can use `region_shrink` to control the method for shrinking each 2x2
2022+
/// region. This defaults to using the average of the 4 input pixels but you can
2023+
/// also use the median in cases where you want to preserve the range of values.
2024+
///
2025+
/// If you set `skip_blanks` to a value greater than or equal to zero, tiles
2026+
/// which are all within that many pixel values to the background are skipped.
2027+
/// This can save a lot of space for some image types. This option defaults to
2028+
/// 5 in Google layout mode, -1 otherwise.
2029+
///
2030+
/// In IIIF layout, you can set the base of the `id` property in `info.json`
2031+
/// with `id`. The default is `https://example.com/iiif`.
2032+
///
2033+
/// Use `layout` [VipsForeignDzLayout#FOREIGN_DZ_LAYOUT_IIIF3] for IIIF v3 layout.
2034+
///
2035+
/// See also: [VImage#tiffsave]
2036+
/// @param filename Filename to save to
2037+
/// @param args Array of VipsOption to apply to this operation
2038+
/// @optionalArg dirname [VipsOption.String] Directory name to save to
2039+
/// @optionalArg imagename [VipsOption.String] Image name
2040+
/// @optionalArg layout [VipsOption.Enum] [VipsForeignDzLayout] Directory layout
2041+
/// @optionalArg suffix [VipsOption.String] Filename suffix for tiles
2042+
/// @optionalArg overlap [VipsOption.Int] Tile overlap in pixels
2043+
/// @optionalArg tile-size [VipsOption.Int] Tile size in pixels
2044+
/// @optionalArg tile-height [VipsOption.Int] Tile height in pixels
2045+
/// @optionalArg tile-width [VipsOption.Int] Tile width in pixels
2046+
/// @optionalArg centre [VipsOption.Boolean] Center image in tile
2047+
/// @optionalArg depth [VipsOption.Enum] [VipsForeignDzDepth] Pyramid depth
2048+
/// @optionalArg angle [VipsOption.Enum] [VipsAngle] Rotate image during save
2049+
/// @optionalArg container [VipsOption.Enum] [VipsForeignDzContainer] Pyramid container type
2050+
/// @optionalArg properties [VipsOption.Boolean] Write a properties file to the output directory
2051+
/// @optionalArg compression [VipsOption.Int] ZIP deflate compression level
2052+
/// @optionalArg region-shrink [VipsOption.Enum] [VipsRegionShrink] Method to shrink regions
2053+
/// @optionalArg skip-blanks [VipsOption.Int] Skip tiles which are nearly equal to the background
2054+
/// @optionalArg id [VipsOption.String] Resource ID
2055+
/// @optionalArg Q [VipsOption.Int] Q factor
2056+
/// @optionalArg no-strip [VipsOption.Boolean] Don't strip tile metadata
2057+
/// @optionalArg basename [VipsOption.String] Base name to save to
2058+
/// @optionalArg keep [VipsOption.Int] Which metadata to retain
2059+
/// @optionalArg background [VipsOption.ArrayDouble] Background value
2060+
/// @optionalArg page-height [VipsOption.Int] Set page height for multipage save
2061+
/// @optionalArg profile [VipsOption.String] Filename of ICC profile to embed
2062+
/// @optionalArg strip [VipsOption.Boolean] Strip all metadata from image
2063+
public void dzsave(String filename, VipsOption... args) throws VipsError {
2064+
var inOption = VipsOption.Image("in", this);
2065+
var filenameOption = VipsOption.String("filename", filename);
2066+
var callArgs = new ArrayList<>(Arrays.asList(args));
2067+
callArgs.add(inOption);
2068+
callArgs.add(filenameOption);
2069+
VipsInvoker.invokeOperation(arena, "dzsave", callArgs);
2070+
}
2071+
2072+
/// As [VImage#dzsave], but save to a memory buffer.
2073+
///
2074+
/// Output is always in a zip container. Use `basename` to set the name of the
2075+
/// directory that the zip will create when unzipped.
2076+
///
2077+
/// The address of the buffer is returned in `buf`, the length of the buffer in
2078+
/// `len`. You are responsible for freeing the buffer with `GLib.free` when you
2079+
/// are done with it.
2080+
///
2081+
/// See also: [VImage#dzsave], `Image.write_to_file`
2082+
/// @param args Array of VipsOption to apply to this operation
2083+
/// @optionalArg dirname [VipsOption.String] Directory name to save to
2084+
/// @optionalArg imagename [VipsOption.String] Image name
2085+
/// @optionalArg layout [VipsOption.Enum] [VipsForeignDzLayout] Directory layout
2086+
/// @optionalArg suffix [VipsOption.String] Filename suffix for tiles
2087+
/// @optionalArg overlap [VipsOption.Int] Tile overlap in pixels
2088+
/// @optionalArg tile-size [VipsOption.Int] Tile size in pixels
2089+
/// @optionalArg tile-height [VipsOption.Int] Tile height in pixels
2090+
/// @optionalArg tile-width [VipsOption.Int] Tile width in pixels
2091+
/// @optionalArg centre [VipsOption.Boolean] Center image in tile
2092+
/// @optionalArg depth [VipsOption.Enum] [VipsForeignDzDepth] Pyramid depth
2093+
/// @optionalArg angle [VipsOption.Enum] [VipsAngle] Rotate image during save
2094+
/// @optionalArg container [VipsOption.Enum] [VipsForeignDzContainer] Pyramid container type
2095+
/// @optionalArg properties [VipsOption.Boolean] Write a properties file to the output directory
2096+
/// @optionalArg compression [VipsOption.Int] ZIP deflate compression level
2097+
/// @optionalArg region-shrink [VipsOption.Enum] [VipsRegionShrink] Method to shrink regions
2098+
/// @optionalArg skip-blanks [VipsOption.Int] Skip tiles which are nearly equal to the background
2099+
/// @optionalArg id [VipsOption.String] Resource ID
2100+
/// @optionalArg Q [VipsOption.Int] Q factor
2101+
/// @optionalArg no-strip [VipsOption.Boolean] Don't strip tile metadata
2102+
/// @optionalArg basename [VipsOption.String] Base name to save to
2103+
/// @optionalArg keep [VipsOption.Int] Which metadata to retain
2104+
/// @optionalArg background [VipsOption.ArrayDouble] Background value
2105+
/// @optionalArg page-height [VipsOption.Int] Set page height for multipage save
2106+
/// @optionalArg profile [VipsOption.String] Filename of ICC profile to embed
2107+
/// @optionalArg strip [VipsOption.Boolean] Strip all metadata from image
2108+
public VBlob dzsaveBuffer(VipsOption... args) throws VipsError {
2109+
var inOption = VipsOption.Image("in", this);
2110+
var bufferOption = VipsOption.Blob("buffer");
2111+
var callArgs = new ArrayList<>(Arrays.asList(args));
2112+
callArgs.add(inOption);
2113+
callArgs.add(bufferOption);
2114+
VipsInvoker.invokeOperation(arena, "dzsave_buffer", callArgs);
2115+
return bufferOption.valueOrThrow();
2116+
}
2117+
2118+
/// As [VImage#dzsave], but save to a target.
2119+
///
2120+
/// See also: [VImage#dzsave], `Image.write_to_target`
2121+
/// @param target Target to save to
2122+
/// @param args Array of VipsOption to apply to this operation
2123+
/// @optionalArg dirname [VipsOption.String] Directory name to save to
2124+
/// @optionalArg imagename [VipsOption.String] Image name
2125+
/// @optionalArg layout [VipsOption.Enum] [VipsForeignDzLayout] Directory layout
2126+
/// @optionalArg suffix [VipsOption.String] Filename suffix for tiles
2127+
/// @optionalArg overlap [VipsOption.Int] Tile overlap in pixels
2128+
/// @optionalArg tile-size [VipsOption.Int] Tile size in pixels
2129+
/// @optionalArg tile-height [VipsOption.Int] Tile height in pixels
2130+
/// @optionalArg tile-width [VipsOption.Int] Tile width in pixels
2131+
/// @optionalArg centre [VipsOption.Boolean] Center image in tile
2132+
/// @optionalArg depth [VipsOption.Enum] [VipsForeignDzDepth] Pyramid depth
2133+
/// @optionalArg angle [VipsOption.Enum] [VipsAngle] Rotate image during save
2134+
/// @optionalArg container [VipsOption.Enum] [VipsForeignDzContainer] Pyramid container type
2135+
/// @optionalArg properties [VipsOption.Boolean] Write a properties file to the output directory
2136+
/// @optionalArg compression [VipsOption.Int] ZIP deflate compression level
2137+
/// @optionalArg region-shrink [VipsOption.Enum] [VipsRegionShrink] Method to shrink regions
2138+
/// @optionalArg skip-blanks [VipsOption.Int] Skip tiles which are nearly equal to the background
2139+
/// @optionalArg id [VipsOption.String] Resource ID
2140+
/// @optionalArg Q [VipsOption.Int] Q factor
2141+
/// @optionalArg no-strip [VipsOption.Boolean] Don't strip tile metadata
2142+
/// @optionalArg basename [VipsOption.String] Base name to save to
2143+
/// @optionalArg keep [VipsOption.Int] Which metadata to retain
2144+
/// @optionalArg background [VipsOption.ArrayDouble] Background value
2145+
/// @optionalArg page-height [VipsOption.Int] Set page height for multipage save
2146+
/// @optionalArg profile [VipsOption.String] Filename of ICC profile to embed
2147+
/// @optionalArg strip [VipsOption.Boolean] Strip all metadata from image
2148+
public void dzsaveTarget(VTarget target, VipsOption... args) throws VipsError {
2149+
var inOption = VipsOption.Image("in", this);
2150+
var targetOption = VipsOption.Target("target", target);
2151+
var callArgs = new ArrayList<>(Arrays.asList(args));
2152+
callArgs.add(inOption);
2153+
callArgs.add(targetOption);
2154+
VipsInvoker.invokeOperation(arena, "dzsave_target", callArgs);
2155+
}
2156+
19772157
/// The opposite of [VImage#extractArea]: embed `in` within an image of
19782158
/// size `width` by `height` at position `x`, `y`.
19792159
///
@@ -2183,7 +2363,7 @@ public VImage fillNearest(VipsOption... args) throws VipsError {
21832363
/// @optionalArg threshold [VipsOption.Double] Object threshold
21842364
/// @optionalArg background [VipsOption.ArrayDouble] Color for background pixels
21852365
/// @optionalArg line-art [VipsOption.Boolean] Enable line art mode
2186-
public int findTrim(VipsOption... args) throws VipsError {
2366+
public FindTrimOutput findTrim(VipsOption... args) throws VipsError {
21872367
var inOption = VipsOption.Image("in", this);
21882368
var leftOption = VipsOption.Int("left");
21892369
var topOption = VipsOption.Int("top");
@@ -2196,7 +2376,7 @@ public int findTrim(VipsOption... args) throws VipsError {
21962376
callArgs.add(widthOption);
21972377
callArgs.add(heightOption);
21982378
VipsInvoker.invokeOperation(arena, "find_trim", callArgs);
2199-
return leftOption.valueOrThrow();
2379+
return new FindTrimOutput(leftOption.valueOrThrow(), topOption.valueOrThrow(), widthOption.valueOrThrow(), heightOption.valueOrThrow());
22002380
}
22012381

22022382
/// Read a FITS image file into a VIPS image.
@@ -6495,7 +6675,9 @@ public static VImage ppmload(Arena arena, String filename, VipsOption... args) t
64956675
return outOption.valueOrThrow();
64966676
}
64976677

6498-
/// Load ppm from buffer
6678+
/// Exactly as [VImage#ppmload], but read from a memory source.
6679+
///
6680+
/// See also: [VImage#ppmload]
64996681
/// @param arena The arena that bounds resulting memory allocations during this operation
65006682
/// @param buffer Buffer to load from
65016683
/// @param args Array of VipsOption to apply to this operation
@@ -6666,7 +6848,7 @@ public VImage prewitt(VipsOption... args) throws VipsError {
66666848
///
66676849
/// See also: [VImage#project], [VImage#histFind]
66686850
/// @param args Array of VipsOption to apply to this operation
6669-
public VImage profile(VipsOption... args) throws VipsError {
6851+
public ProfileOutput profile(VipsOption... args) throws VipsError {
66706852
var inOption = VipsOption.Image("in", this);
66716853
var columnsOption = VipsOption.Image("columns");
66726854
var rowsOption = VipsOption.Image("rows");
@@ -6675,7 +6857,7 @@ public VImage profile(VipsOption... args) throws VipsError {
66756857
callArgs.add(columnsOption);
66766858
callArgs.add(rowsOption);
66776859
VipsInvoker.invokeOperation(arena, "profile", callArgs);
6678-
return columnsOption.valueOrThrow();
6860+
return new ProfileOutput(columnsOption.valueOrThrow(), rowsOption.valueOrThrow());
66796861
}
66806862

66816863
/// Find the horizontal and vertical projections of an image, ie. the sum
@@ -6686,7 +6868,7 @@ public VImage profile(VipsOption... args) throws VipsError {
66866868
///
66876869
/// See also: [VImage#histFind], [VImage#profile]
66886870
/// @param args Array of VipsOption to apply to this operation
6689-
public VImage project(VipsOption... args) throws VipsError {
6871+
public ProjectOutput project(VipsOption... args) throws VipsError {
66906872
var inOption = VipsOption.Image("in", this);
66916873
var columnsOption = VipsOption.Image("columns");
66926874
var rowsOption = VipsOption.Image("rows");
@@ -6695,7 +6877,7 @@ public VImage project(VipsOption... args) throws VipsError {
66956877
callArgs.add(columnsOption);
66966878
callArgs.add(rowsOption);
66976879
VipsInvoker.invokeOperation(arena, "project", callArgs);
6698-
return columnsOption.valueOrThrow();
6880+
return new ProjectOutput(columnsOption.valueOrThrow(), rowsOption.valueOrThrow());
66996881
}
67006882

67016883
/// Transform an image with a 0, 1, 2, or 3rd order polynomial.
@@ -9935,4 +10117,16 @@ public List<String> getFields() {
993510117
VipsRaw.vips_image_map(this.address, callbackPointer, MemorySegment.NULL);
993610118
return fieldNameStrings;
993710119
}
10120+
10121+
/// Helper record to hold multiple outputs from the [VImage#findTrim] operation
10122+
public record FindTrimOutput(int left, int top, int width, int height) {
10123+
}
10124+
10125+
/// Helper record to hold multiple outputs from the [VImage#profile] operation
10126+
public record ProfileOutput(VImage columns, VImage rows) {
10127+
}
10128+
10129+
/// Helper record to hold multiple outputs from the [VImage#project] operation
10130+
public record ProjectOutput(VImage columns, VImage rows) {
10131+
}
993810132
}

0 commit comments

Comments
 (0)