diff --git a/pom.xml b/pom.xml
index 4f09a984f..8e16429ca 100644
--- a/pom.xml
+++ b/pom.xml
@@ -209,6 +209,11 @@
n5
2.1.6
+
+ org.janelia.saalfeldlab
+ n5-aws-s3
+ 2.1.1-SNAPSHOT
+
com.miglayout
miglayout-swing
diff --git a/src/main/java/bdv/export/n5/WriteSequenceToN5.java b/src/main/java/bdv/export/n5/WriteSequenceToN5.java
index 62f5cc97c..7cb45b55a 100644
--- a/src/main/java/bdv/export/n5/WriteSequenceToN5.java
+++ b/src/main/java/bdv/export/n5/WriteSequenceToN5.java
@@ -8,7 +8,7 @@
import bdv.export.ExportScalePyramid.AfterEachPlane;
import bdv.export.ExportScalePyramid.LoopbackHeuristic;
import bdv.img.cache.SimpleCacheArrayLoader;
-import bdv.img.n5.N5ImageLoader;
+import bdv.img.n5.N5FSImageLoader;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -325,7 +325,7 @@ public RandomAccessibleInterval< T > getImage( final int level ) throws IOExcept
final long[] dimensions = attributes.getDimensions();
final int[] cellDimensions = attributes.getBlockSize();
final CellGrid grid = new CellGrid( dimensions, cellDimensions );
- final SimpleCacheArrayLoader< ? > cacheArrayLoader = N5ImageLoader.createCacheArrayLoader( n5, pathName );
+ final SimpleCacheArrayLoader< ? > cacheArrayLoader = N5FSImageLoader.createCacheArrayLoader( n5, pathName );
return new ReadOnlyCachedCellImgFactory().createWithCacheLoader(
dimensions, type,
key -> {
diff --git a/src/main/java/bdv/img/n5/N5FSImageLoader.java b/src/main/java/bdv/img/n5/N5FSImageLoader.java
new file mode 100644
index 000000000..c631705e8
--- /dev/null
+++ b/src/main/java/bdv/img/n5/N5FSImageLoader.java
@@ -0,0 +1,52 @@
+/*
+ * #%L
+ * BigDataViewer core classes with minimal dependencies
+ * %%
+ * Copyright (C) 2012 - 2016 Tobias Pietzsch, Stephan Saalfeld, Stephan Preibisch,
+ * Jean-Yves Tinevez, HongKee Moon, Johannes Schindelin, Curtis Rueden, John Bogovic
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.img.n5;
+
+import mpicbg.spim.data.generic.sequence.AbstractSequenceDescription;
+import org.janelia.saalfeldlab.n5.N5FSReader;
+
+import java.io.File;
+import java.io.IOException;
+
+public class N5FSImageLoader extends N5ImageLoader
+{
+ private final File n5File;
+
+ public N5FSImageLoader( final File n5File, final AbstractSequenceDescription< ?, ?, ? > sequenceDescription ) throws IOException
+ {
+ super( new N5FSReader( n5File.getAbsolutePath() ), sequenceDescription );
+ this.n5File = n5File;
+ }
+
+ public File getN5File()
+ {
+ return n5File;
+ }
+}
diff --git a/src/main/java/bdv/img/n5/N5ImageLoader.java b/src/main/java/bdv/img/n5/N5ImageLoader.java
index 3a774d0b1..22b035ba7 100644
--- a/src/main/java/bdv/img/n5/N5ImageLoader.java
+++ b/src/main/java/bdv/img/n5/N5ImageLoader.java
@@ -36,98 +36,63 @@
import bdv.img.cache.VolatileGlobalCellCache;
import bdv.util.ConstantRandomAccessible;
import bdv.util.MipmapTransforms;
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.function.Function;
+import com.amazonaws.SdkClientException;
import mpicbg.spim.data.generic.sequence.AbstractSequenceDescription;
import mpicbg.spim.data.generic.sequence.BasicViewSetup;
import mpicbg.spim.data.generic.sequence.ImgLoaderHint;
import mpicbg.spim.data.sequence.MultiResolutionImgLoader;
import mpicbg.spim.data.sequence.MultiResolutionSetupImgLoader;
import mpicbg.spim.data.sequence.VoxelDimensions;
-import net.imglib2.Dimensions;
-import net.imglib2.FinalDimensions;
-import net.imglib2.FinalInterval;
-import net.imglib2.RandomAccessibleInterval;
-import net.imglib2.Volatile;
+import net.imglib2.*;
import net.imglib2.cache.queue.BlockingFetchQueues;
import net.imglib2.cache.queue.FetcherThreads;
import net.imglib2.cache.volatiles.CacheHints;
import net.imglib2.cache.volatiles.LoadingStrategy;
-import net.imglib2.img.basictypeaccess.volatiles.array.VolatileByteArray;
-import net.imglib2.img.basictypeaccess.volatiles.array.VolatileDoubleArray;
-import net.imglib2.img.basictypeaccess.volatiles.array.VolatileFloatArray;
-import net.imglib2.img.basictypeaccess.volatiles.array.VolatileIntArray;
-import net.imglib2.img.basictypeaccess.volatiles.array.VolatileLongArray;
-import net.imglib2.img.basictypeaccess.volatiles.array.VolatileShortArray;
+import net.imglib2.img.basictypeaccess.volatiles.array.*;
import net.imglib2.img.cell.CellGrid;
import net.imglib2.img.cell.CellImg;
import net.imglib2.realtransform.AffineTransform3D;
import net.imglib2.type.NativeType;
-import net.imglib2.type.numeric.integer.ByteType;
-import net.imglib2.type.numeric.integer.IntType;
-import net.imglib2.type.numeric.integer.LongType;
-import net.imglib2.type.numeric.integer.ShortType;
-import net.imglib2.type.numeric.integer.UnsignedByteType;
-import net.imglib2.type.numeric.integer.UnsignedIntType;
-import net.imglib2.type.numeric.integer.UnsignedLongType;
-import net.imglib2.type.numeric.integer.UnsignedShortType;
+import net.imglib2.type.numeric.integer.*;
import net.imglib2.type.numeric.real.DoubleType;
import net.imglib2.type.numeric.real.FloatType;
-import net.imglib2.type.volatiles.VolatileByteType;
-import net.imglib2.type.volatiles.VolatileDoubleType;
-import net.imglib2.type.volatiles.VolatileFloatType;
-import net.imglib2.type.volatiles.VolatileIntType;
-import net.imglib2.type.volatiles.VolatileLongType;
-import net.imglib2.type.volatiles.VolatileShortType;
-import net.imglib2.type.volatiles.VolatileUnsignedByteType;
-import net.imglib2.type.volatiles.VolatileUnsignedIntType;
-import net.imglib2.type.volatiles.VolatileUnsignedLongType;
-import net.imglib2.type.volatiles.VolatileUnsignedShortType;
+import net.imglib2.type.volatiles.*;
import net.imglib2.util.Cast;
import net.imglib2.view.Views;
-import org.janelia.saalfeldlab.n5.DataBlock;
-import org.janelia.saalfeldlab.n5.DataType;
-import org.janelia.saalfeldlab.n5.DatasetAttributes;
-import org.janelia.saalfeldlab.n5.N5FSReader;
-import org.janelia.saalfeldlab.n5.N5Reader;
+import org.janelia.saalfeldlab.n5.*;
-import static bdv.img.n5.BdvN5Format.DATA_TYPE_KEY;
-import static bdv.img.n5.BdvN5Format.DOWNSAMPLING_FACTORS_KEY;
-import static bdv.img.n5.BdvN5Format.getPathName;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.function.Function;
+
+import static bdv.img.n5.BdvN5Format.*;
public class N5ImageLoader implements ViewerImgLoader, MultiResolutionImgLoader
{
- private final File n5File;
+ protected final N5Reader n5;
// TODO: it would be good if this would not be needed
// find available setups from the n5
- private final AbstractSequenceDescription< ?, ?, ? > seq;
+ protected final AbstractSequenceDescription< ?, ?, ? > seq;
/**
* Maps setup id to {@link SetupImgLoader}.
*/
private final Map< Integer, SetupImgLoader > setupImgLoaders = new HashMap<>();
- public N5ImageLoader( final File n5File, final AbstractSequenceDescription< ?, ?, ? > sequenceDescription )
- {
- this.n5File = n5File;
- this.seq = sequenceDescription;
- }
-
- public File getN5File()
- {
- return n5File;
- }
-
private volatile boolean isOpen = false;
private FetcherThreads fetchers;
private VolatileGlobalCellCache cache;
- private N5Reader n5;
+
+ public N5ImageLoader( N5Reader n5Reader, AbstractSequenceDescription< ?, ?, ? > sequenceDescription )
+ {
+ this.n5 = n5Reader;
+ this.seq = sequenceDescription;
+ }
private void open()
{
@@ -140,8 +105,6 @@ private void open()
try
{
- this.n5 = new N5FSReader( n5File.getAbsolutePath() );
-
int maxNumLevels = 0;
final List< ? extends BasicViewSetup > setups = seq.getViewSetupsOrdered();
for ( final BasicViewSetup setup : setups )
@@ -353,7 +316,46 @@ private static class N5CacheArrayLoader< A > implements SimpleCacheArrayLoader<
@Override
public A loadArray( final long[] gridPosition ) throws IOException
{
- return createArray.apply( n5.readBlock( pathName, attributes, gridPosition ) );
+ DataBlock< ? > block = null;
+
+ try {
+ block = n5.readBlock( pathName, attributes, gridPosition );
+ }
+ catch ( SdkClientException e )
+ {
+ System.err.println( e ); // this happens sometimes, not sure yet why...
+ }
+
+ if ( block == null )
+ {
+ final int[] blockSize = attributes.getBlockSize();
+ final int n = blockSize[ 0 ] * blockSize[ 1 ] * blockSize[ 2 ];
+ switch ( attributes.getDataType() )
+ {
+ case UINT8:
+ case INT8:
+ return createArray.apply( new ByteArrayDataBlock( blockSize, gridPosition, new byte[ n ] ) );
+ case UINT16:
+ case INT16:
+ return createArray.apply( new ShortArrayDataBlock( blockSize, gridPosition, new short[ n ] ) );
+ case UINT32:
+ case INT32:
+ return createArray.apply( new IntArrayDataBlock( blockSize, gridPosition, new int[ n ] ) );
+ case UINT64:
+ case INT64:
+ return createArray.apply( new LongArrayDataBlock( blockSize, gridPosition, new long[ n ] ) );
+ case FLOAT32:
+ return createArray.apply( new FloatArrayDataBlock( blockSize, gridPosition, new float[ n ] ) );
+ case FLOAT64:
+ return createArray.apply( new DoubleArrayDataBlock( blockSize, gridPosition, new double[ n ] ) );
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+ else
+ {
+ return createArray.apply( block );
+ }
}
}
diff --git a/src/main/java/bdv/img/n5/N5S3ImageLoader.java b/src/main/java/bdv/img/n5/N5S3ImageLoader.java
new file mode 100644
index 000000000..555d6d22a
--- /dev/null
+++ b/src/main/java/bdv/img/n5/N5S3ImageLoader.java
@@ -0,0 +1,143 @@
+/*
+ * #%L
+ * BigDataViewer core classes with minimal dependencies
+ * %%
+ * Copyright (C) 2012 - 2016 Tobias Pietzsch, Stephan Saalfeld, Stephan Preibisch,
+ * Jean-Yves Tinevez, HongKee Moon, Johannes Schindelin, Curtis Rueden, John Bogovic
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.img.n5;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.auth.AWSStaticCredentialsProvider;
+import com.amazonaws.auth.AnonymousAWSCredentials;
+import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
+import com.amazonaws.client.builder.AwsClientBuilder;
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.AmazonS3ClientBuilder;
+import mpicbg.spim.data.generic.sequence.AbstractSequenceDescription;
+import org.janelia.saalfeldlab.n5.s3.N5AmazonS3Reader;
+
+import java.io.IOException;
+
+public class N5S3ImageLoader extends N5ImageLoader
+{
+ private final String serviceEndpoint;
+ private final String signingRegion;
+ private final String bucketName;
+ private final String key;
+ private final N5AmazonS3ReaderCreator.Authentication authentication;
+
+ static class N5AmazonS3ReaderCreator
+ {
+ /**
+ * It seems that the way S3 works is that when a user has no credentials it means anonymous,
+ * but as soon as you provide some credentials it tries to get access with those,
+ * which indeed don't have access for that specific bucket.
+ * So it seems the way to go is to define in the application whether
+ * you want to use anonymous access or credentials based access
+ */
+ public enum Authentication
+ {
+ Anonymous,
+ Protected
+ }
+
+ public N5AmazonS3Reader create( String serviceEndpoint, String signingRegion, String bucketName, String key, Authentication authentication ) throws IOException
+ {
+ final AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration( serviceEndpoint, signingRegion );
+
+ final AmazonS3 s3 = AmazonS3ClientBuilder
+ .standard()
+ .withPathStyleAccessEnabled( true )
+ .withEndpointConfiguration( endpoint )
+ .withCredentials( getCredentialsProvider( authentication ) )
+ .build();
+
+ return new N5AmazonS3Reader( s3, bucketName, key );
+ }
+
+ private AWSCredentialsProvider getCredentialsProvider( Authentication authentication )
+ {
+ switch ( authentication )
+ {
+ case Anonymous:
+ return new AWSStaticCredentialsProvider( new AnonymousAWSCredentials() );
+ case Protected:
+ final DefaultAWSCredentialsProviderChain credentialsProvider = new DefaultAWSCredentialsProviderChain();
+ checkCredentialsExistence( credentialsProvider );
+ return credentialsProvider;
+ default:
+ throw new UnsupportedOperationException( "Authentication not supported: " + authentication );
+ }
+ }
+
+ private void checkCredentialsExistence( AWSCredentialsProvider credentialsProvider )
+ {
+ try
+ {
+ credentialsProvider.getCredentials();
+ }
+ catch ( Exception e )
+ {
+ throw new RuntimeException( e ); // No credentials could be found
+ }
+ }
+ }
+
+ public N5S3ImageLoader( String serviceEndpoint, String signingRegion, String bucketName, String key, N5AmazonS3ReaderCreator.Authentication authentication, AbstractSequenceDescription< ?, ?, ? > sequenceDescription ) throws IOException
+ {
+ super( new N5AmazonS3ReaderCreator().create( serviceEndpoint, signingRegion, bucketName, key, authentication ), sequenceDescription );
+ this.serviceEndpoint = serviceEndpoint;
+ this.signingRegion = signingRegion;
+ this.bucketName = bucketName;
+ this.key = key;
+ this.authentication = authentication;
+ }
+
+ public String getServiceEndpoint()
+ {
+ return serviceEndpoint;
+ }
+
+ public String getSigningRegion()
+ {
+ return signingRegion;
+ }
+
+ public String getBucketName()
+ {
+ return bucketName;
+ }
+
+ public String getKey()
+ {
+ return key;
+ }
+
+ public N5AmazonS3ReaderCreator.Authentication getAuthentication()
+ {
+ return authentication;
+ }
+}
diff --git a/src/main/java/bdv/img/n5/XmlIoN5ImageLoader.java b/src/main/java/bdv/img/n5/XmlIoN5FSImageLoader.java
similarity index 75%
rename from src/main/java/bdv/img/n5/XmlIoN5ImageLoader.java
rename to src/main/java/bdv/img/n5/XmlIoN5FSImageLoader.java
index 10e40feb6..a0ae90079 100644
--- a/src/main/java/bdv/img/n5/XmlIoN5ImageLoader.java
+++ b/src/main/java/bdv/img/n5/XmlIoN5FSImageLoader.java
@@ -30,6 +30,8 @@
package bdv.img.n5;
import java.io.File;
+import java.io.IOException;
+
import mpicbg.spim.data.XmlHelpers;
import mpicbg.spim.data.generic.sequence.AbstractSequenceDescription;
import mpicbg.spim.data.generic.sequence.ImgLoaderIo;
@@ -39,24 +41,33 @@
import static mpicbg.spim.data.XmlHelpers.loadPath;
import static mpicbg.spim.data.XmlKeys.IMGLOADER_FORMAT_ATTRIBUTE_NAME;
-@ImgLoaderIo( format = "bdv.n5", type = N5ImageLoader.class )
-public class XmlIoN5ImageLoader implements XmlIoBasicImgLoader< N5ImageLoader >
+@ImgLoaderIo( format = "bdv.n5", type = N5FSImageLoader.class )
+public class XmlIoN5FSImageLoader implements XmlIoBasicImgLoader< N5FSImageLoader >
{
+ public static final String N5 = "n5";
+
@Override
- public Element toXml( final N5ImageLoader imgLoader, final File basePath )
+ public Element toXml( final N5FSImageLoader imgLoader, final File basePath )
{
final Element elem = new Element( "ImageLoader" );
elem.setAttribute( IMGLOADER_FORMAT_ATTRIBUTE_NAME, "bdv.n5" );
elem.setAttribute( "version", "1.0" );
- elem.addContent( XmlHelpers.pathElement( "n5", imgLoader.getN5File(), basePath ) );
+ elem.addContent( XmlHelpers.pathElement( N5, imgLoader.getN5File(), basePath ) );
return elem;
}
@Override
- public N5ImageLoader fromXml( final Element elem, final File basePath, final AbstractSequenceDescription< ?, ?, ? > sequenceDescription )
+ public N5FSImageLoader fromXml( final Element elem, final File basePath, final AbstractSequenceDescription< ?, ?, ? > sequenceDescription )
{
// final String version = elem.getAttributeValue( "version" );
- final File path = loadPath( elem, "n5", basePath );
- return new N5ImageLoader( path, sequenceDescription );
+ final File path = loadPath( elem, N5, basePath );
+ try
+ {
+ return new N5FSImageLoader( path, sequenceDescription );
+ }
+ catch ( IOException e )
+ {
+ throw new RuntimeException( e );
+ }
}
}
diff --git a/src/main/java/bdv/img/n5/XmlIoN5S3ImageLoader.java b/src/main/java/bdv/img/n5/XmlIoN5S3ImageLoader.java
new file mode 100644
index 000000000..ab0894bc8
--- /dev/null
+++ b/src/main/java/bdv/img/n5/XmlIoN5S3ImageLoader.java
@@ -0,0 +1,90 @@
+/*
+ * #%L
+ * BigDataViewer core classes with minimal dependencies
+ * %%
+ * Copyright (C) 2012 - 2016 Tobias Pietzsch, Stephan Saalfeld, Stephan Preibisch,
+ * Jean-Yves Tinevez, HongKee Moon, Johannes Schindelin, Curtis Rueden, John Bogovic
+ * %%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ * #L%
+ */
+package bdv.img.n5;
+
+import mpicbg.spim.data.XmlHelpers;
+import mpicbg.spim.data.generic.sequence.AbstractSequenceDescription;
+import mpicbg.spim.data.generic.sequence.ImgLoaderIo;
+import mpicbg.spim.data.generic.sequence.XmlIoBasicImgLoader;
+import org.jdom2.Element;
+
+import java.io.File;
+import java.io.IOException;
+
+import static bdv.img.n5.N5S3ImageLoader.N5AmazonS3ReaderCreator.*;
+import static mpicbg.spim.data.XmlKeys.IMGLOADER_FORMAT_ATTRIBUTE_NAME;
+
+@ImgLoaderIo( format = "bdv.n5.s3", type = N5FSImageLoader.class )
+public class XmlIoN5S3ImageLoader implements XmlIoBasicImgLoader< N5S3ImageLoader >
+{
+ public static final String SERVICE_ENDPOINT = "ServiceEndpoint";
+ public static final String SIGNING_REGION = "SigningRegion";
+ public static final String BUCKET_NAME = "BucketName";
+ public static final String KEY = "Key";
+ public static final String AUTHENTICATION = "Authentication";
+
+
+ @Override
+ public Element toXml( final N5S3ImageLoader imgLoader, final File basePath )
+ {
+ final Element elem = new Element( "ImageLoader" );
+ elem.setAttribute( IMGLOADER_FORMAT_ATTRIBUTE_NAME, "bdv.n5.s3" );
+ elem.setAttribute( "version", "1.0" );
+ elem.setAttribute( SERVICE_ENDPOINT, imgLoader.getServiceEndpoint() );
+ elem.setAttribute( SIGNING_REGION, imgLoader.getSigningRegion() );
+ elem.setAttribute( BUCKET_NAME, imgLoader.getBucketName() );
+ elem.setAttribute( KEY, imgLoader.getKey() );
+ elem.setAttribute( AUTHENTICATION, imgLoader.getAuthentication().toString() );
+
+ return elem;
+ }
+
+ @Override
+ public N5S3ImageLoader fromXml( final Element elem, final File basePath, final AbstractSequenceDescription< ?, ?, ? > sequenceDescription )
+ {
+// final String version = elem.getAttributeValue( "version" );
+
+ final String serviceEndpoint = XmlHelpers.getText( elem, SERVICE_ENDPOINT );
+ final String signingRegion = XmlHelpers.getText( elem, SIGNING_REGION );
+ final String bucketName = XmlHelpers.getText( elem, BUCKET_NAME );
+ final String key = XmlHelpers.getText( elem, KEY );
+ final Authentication authentication = Authentication.valueOf( XmlHelpers.getText( elem, AUTHENTICATION ) );
+
+
+ try
+ {
+ return new N5S3ImageLoader( serviceEndpoint, signingRegion, bucketName, key, authentication, sequenceDescription );
+ }
+ catch ( IOException e )
+ {
+ throw new RuntimeException( e );
+ }
+ }
+}
diff --git a/src/test/java/bdv/n5/N5S3Example.java b/src/test/java/bdv/n5/N5S3Example.java
new file mode 100644
index 000000000..a2e74cd04
--- /dev/null
+++ b/src/test/java/bdv/n5/N5S3Example.java
@@ -0,0 +1,13 @@
+package bdv.n5;
+
+import bdv.BigDataViewer;
+import bdv.viewer.ViewerOptions;
+import mpicbg.spim.data.SpimDataException;
+
+public class N5S3Example
+{
+ public static void main( String[] args ) throws SpimDataException
+ {
+ BigDataViewer.open( "https://raw.githubusercontent.com/platybrowser/platybrowser/master/data/1.0.1/images/remote/prospr-6dpf-1-whole-ache.xml", "", null, ViewerOptions.options().numRenderingThreads( 3 ) );
+ }
+}