diff --git a/src/main/java/azgracompress/ViewerCompressionOptions.java b/src/main/java/azgracompress/ViewerCompressionOptions.java deleted file mode 100644 index c74cd3c181a707bb92f4ae775a54c1a846495163..0000000000000000000000000000000000000000 --- a/src/main/java/azgracompress/ViewerCompressionOptions.java +++ /dev/null @@ -1,22 +0,0 @@ -package azgracompress; - -public class ViewerCompressionOptions { - private boolean enabled = false; - private int compressFromMipmapLevel = 0; - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(final boolean enable) { - this.enabled = enable; - } - - public int getCompressFromMipmapLevel() { - return compressFromMipmapLevel; - } - - public void setCompressFromMipmapLevel(final int compressFrom) { - this.compressFromMipmapLevel = compressFrom; - } -} diff --git a/src/main/java/bdv/BigDataViewer.java b/src/main/java/bdv/BigDataViewer.java index 2756ebff4497eb0a76a7500a94c50651bc83e13d..df3644ad2d832778de00296be7ff84795f47f53f 100644 --- a/src/main/java/bdv/BigDataViewer.java +++ b/src/main/java/bdv/BigDataViewer.java @@ -28,7 +28,6 @@ */ package bdv; -import azgracompress.ViewerCompressionOptions; import azgracompress.utilities.ColorConsole; import bdv.cache.CacheControl; import bdv.export.ProgressWriter; @@ -93,619 +92,576 @@ public class BigDataViewer { protected final RecordMovieDialog movieDialog; - protected final BrightnessDialog brightnessDialog; - - protected final RecordMaxProjectionDialog movieMaxProjectDialog; - - protected final VisibilityAndGroupingDialog activeSourcesDialog; - - protected final HelpDialog helpDialog; - - protected final ManualTransformationEditor manualTransformationEditor; - - protected final BookmarksEditor bookmarkEditor; - - protected final JFileChooser fileChooser; - - protected File proposedSettingsFile; - - public void toggleManualTransformation() - { - manualTransformationEditor.toggle(); - } - - public void initSetBookmark() - { - bookmarkEditor.initSetBookmark(); - } - - public void initGoToBookmark() - { - bookmarkEditor.initGoToBookmark(); - } - - public void initGoToBookmarkRotation() - { - bookmarkEditor.initGoToBookmarkRotation(); - } - - private static String createSetupName( final BasicViewSetup setup ) - { - if ( setup.hasName() ) - return setup.getName(); - - String name = ""; - - final Angle angle = setup.getAttribute( Angle.class ); - if ( angle != null ) - name += ( name.isEmpty() ? "" : " " ) + "a " + angle.getName(); - - final Channel channel = setup.getAttribute( Channel.class ); - if ( channel != null ) - name += ( name.isEmpty() ? "" : " " ) + "c " + channel.getName(); - - return name; - } - - /** - * Create standard converter from the given {@code type} to ARGB: - * <ul> - * <li>For {@code RealType}s a {@link RealARGBColorConverter} is - * returned.</li> - * <li>For {@code ARGBType}s a {@link ScaledARGBConverter.ARGB} is - * returned.</li> - * <li>For {@code VolatileARGBType}s a - * {@link ScaledARGBConverter.VolatileARGB} is returned.</li> - * </ul> - */ - @SuppressWarnings( "unchecked" ) - public static < T extends NumericType< T > > Converter< T, ARGBType > createConverterToARGB( final T type ) - { - if ( type instanceof RealType ) - { - final RealType< ? > t = ( RealType< ? > ) type; - final double typeMin = Math.max( 0, Math.min( t.getMinValue(), 65535 ) ); - final double typeMax = Math.max( 0, Math.min( t.getMaxValue(), 65535 ) ); - return ( Converter< T, ARGBType > ) RealARGBColorConverter.create( t, typeMin, typeMax ); - } - else if ( type instanceof ARGBType ) - return ( Converter< T, ARGBType > ) new ScaledARGBConverter.ARGB( 0, 255 ); - else if ( type instanceof VolatileARGBType ) - return ( Converter< T, ARGBType > ) new ScaledARGBConverter.VolatileARGB( 0, 255 ); - else - throw new IllegalArgumentException( "ImgLoader of type " + type.getClass() + " not supported." ); - } - - /** - * Create a {@code ConverterSetup} for the given {@code SourceAndConverter}. - * {@link SourceAndConverter#asVolatile() Nested volatile} - * {@code SourceAndConverter} are added to the {@code ConverterSetup} if - * present. If {@code SourceAndConverter} does not comprise a - * {@code ColorConverter}, returns {@code null}. - * - * @param soc - * {@code SourceAndConverter} for which to create a - * {@code ConverterSetup} - * @param setupId - * setupId of the created {@code ConverterSetup} - * @return a new {@code ConverterSetup} or {@code null} - */ - public static ConverterSetup createConverterSetup( final SourceAndConverter< ? > soc, final int setupId ) - { - final List< ColorConverter > converters = new ArrayList<>(); - - final Converter< ?, ARGBType > c = soc.getConverter(); - if ( c instanceof ColorConverter ) - converters.add( ( ColorConverter ) c ); - - final SourceAndConverter< ? extends Volatile< ? > > vsoc = soc.asVolatile(); - if ( vsoc != null ) - { - final Converter< ?, ARGBType > vc = vsoc.getConverter(); - if ( vc instanceof ColorConverter ) - converters.add( ( ColorConverter ) vc ); - } - - if ( converters.isEmpty() ) - return null; - else - return new RealARGBColorConverterSetup( setupId, converters ); - } - - /** - * Decorate source with an extra transformation, that can be edited manually - * in this viewer. {@link SourceAndConverter#asVolatile() Nested volatile} - * {@code SourceAndConverter} are wrapped as well, if present. - */ - public static < T, V extends Volatile< T > > SourceAndConverter< T > wrapWithTransformedSource( final SourceAndConverter< T > soc ) - { - if ( soc.asVolatile() == null ) - return new SourceAndConverter<>( new TransformedSource<>( soc.getSpimSource() ), soc.getConverter() ); - - @SuppressWarnings( "unchecked" ) - final SourceAndConverter< V > vsoc = ( SourceAndConverter< V > ) soc.asVolatile(); - final TransformedSource< T > ts = new TransformedSource<>( soc.getSpimSource() ); - final TransformedSource< V > vts = new TransformedSource<>( vsoc.getSpimSource(), ts ); - return new SourceAndConverter<>( ts, soc.getConverter(), new SourceAndConverter<>( vts, vsoc.getConverter() ) ); - } - - private static < T extends NumericType< T >, V extends Volatile< T > & NumericType< V > > void initSetupNumericType( - final AbstractSpimData< ? > spimData, - final BasicViewSetup setup, - final List< ConverterSetup > converterSetups, - final List< SourceAndConverter< ? > > sources ) - { - final int setupId = setup.getId(); - final ViewerImgLoader imgLoader = ( ViewerImgLoader ) spimData.getSequenceDescription().getImgLoader(); - @SuppressWarnings( "unchecked" ) - final ViewerSetupImgLoader< T, V > setupImgLoader = ( ViewerSetupImgLoader< T, V > ) imgLoader.getSetupImgLoader( setupId ); - final T type = setupImgLoader.getImageType(); - final V volatileType = setupImgLoader.getVolatileImageType(); - - if ( ! ( type instanceof NumericType ) ) - throw new IllegalArgumentException( "ImgLoader of type " + type.getClass() + " not supported." ); - - final String setupName = createSetupName( setup ); - - SourceAndConverter< V > vsoc = null; - if ( volatileType != null ) - { - final VolatileSpimSource< V > vs = new VolatileSpimSource<>( spimData, setupId, setupName ); - vsoc = new SourceAndConverter<>( vs, createConverterToARGB( volatileType ) ); - } - - final SpimSource< T > s = new SpimSource<>( spimData, setupId, setupName ); - final SourceAndConverter< T > soc = new SourceAndConverter<>( s, createConverterToARGB( type ), vsoc ); - final SourceAndConverter< T > tsoc = wrapWithTransformedSource( soc ); - sources.add( tsoc ); - - final ConverterSetup converterSetup = createConverterSetup( tsoc, setupId ); - if ( converterSetup != null ) - converterSetups.add( converterSetup ); - } - - public static void initSetups( - final AbstractSpimData< ? > spimData, - final List< ConverterSetup > converterSetups, - final List< SourceAndConverter< ? > > sources ) - { - for ( final BasicViewSetup setup : spimData.getSequenceDescription().getViewSetupsOrdered() ) - initSetupNumericType( spimData, setup, converterSetups, sources ); - } - - /** - * - * @param converterSetups - * list of {@link ConverterSetup} that control min/max and color - * of sources. - * @param sources - * list of pairs of source of some type and converter from that - * type to ARGB. - * @param spimData - * may be null. The {@link AbstractSpimData} of the dataset (if - * there is one). If it exists, it is used to set up a "Crop" - * dialog. - * @param numTimepoints - * the number of timepoints in the dataset. - * @param cache - * handle to cache. This is used to control io timing. - * @param windowTitle - * title of the viewer window. - * @param progressWriter - * a {@link ProgressWriter} to which BDV may report progress - * (currently only used in the "Record Movie" dialog). - * @param options - * optional parameters. - */ - public BigDataViewer( - final ArrayList< ConverterSetup > converterSetups, - final ArrayList< SourceAndConverter< ? > > sources, - final AbstractSpimData< ? > spimData, - final int numTimepoints, - final CacheControl cache, - final String windowTitle, - final ProgressWriter progressWriter, - final ViewerOptions options ) - { - final InputTriggerConfig inputTriggerConfig = getInputTriggerConfig( options ); - - viewerFrame = new ViewerFrame( sources, numTimepoints, cache, options.inputTriggerConfig( inputTriggerConfig ) ); - if ( windowTitle != null ) - viewerFrame.setTitle( windowTitle ); - viewer = viewerFrame.getViewerPanel(); - -// final ConverterSetup.SetupChangeListener requestRepaint = s -> viewer.requestRepaint(); -// for ( final ConverterSetup cs : converterSetups ) -// cs.setupChangeListeners().add( requestRepaint ); - - manualTransformation = new ManualTransformation( viewer ); - manualTransformationEditor = new ManualTransformationEditor( viewer, viewerFrame.getKeybindings() ); - - bookmarks = new Bookmarks(); - bookmarkEditor = new BookmarksEditor( viewer, viewerFrame.getKeybindings(), bookmarks ); - - final ConverterSetups setups = viewerFrame.getConverterSetups(); - if ( converterSetups.size() != sources.size() ) - System.err.println( "WARNING! Constructing BigDataViewer, with converterSetups.size() that is not the same as sources.size()." ); - final int numSetups = Math.min( converterSetups.size(), sources.size() ); - for ( int i = 0; i < numSetups; ++i ) - { - final SourceAndConverter< ? > source = sources.get( i ); - final ConverterSetup setup = converterSetups.get( i ); - if ( setup != null ) - setups.put( source, setup ); - } - - setupAssignments = new SetupAssignments( converterSetups, 0, 65535 ); - if ( setupAssignments.getMinMaxGroups().size() > 0 ) - { - final MinMaxGroup group = setupAssignments.getMinMaxGroups().get( 0 ); - for ( final ConverterSetup setup : setupAssignments.getConverterSetups() ) - setupAssignments.moveSetupToGroup( setup, group ); - } - - brightnessDialog = new BrightnessDialog( viewerFrame, setupAssignments ); - - if (spimData != null ) - viewer.getSourceInfoOverlayRenderer().setTimePointsOrdered( spimData.getSequenceDescription().getTimePoints().getTimePointsOrdered() ); - - cropDialog = ( spimData == null ) ? null : new CropDialog( viewerFrame, viewer, spimData.getSequenceDescription() ); - - movieDialog = new RecordMovieDialog( viewerFrame, viewer, progressWriter ); - // this is just to get updates of window size: - viewer.getDisplay().overlays().add( movieDialog ); - - movieMaxProjectDialog = new RecordMaxProjectionDialog( viewerFrame, viewer, progressWriter ); - // this is just to get updates of window size: - viewer.getDisplay().overlays().add( movieMaxProjectDialog ); - - activeSourcesDialog = new VisibilityAndGroupingDialog( viewerFrame, viewer.state() ); - - helpDialog = new HelpDialog( viewerFrame ); - - fileChooser = new JFileChooser(); - fileChooser.setFileFilter( new FileFilter() - { - @Override - public String getDescription() - { - return "xml files"; - } - - @Override - public boolean accept( final File f ) - { - if ( f.isDirectory() ) - return true; - if ( f.isFile() ) - { - final String s = f.getName(); - final int i = s.lastIndexOf( '.' ); - if ( i > 0 && i < s.length() - 1 ) - { - final String ext = s.substring( i + 1 ).toLowerCase(); - return ext.equals( "xml" ); - } - } - return false; - } - } ); - - NavigationActions.installActionBindings( viewerFrame.getKeybindings(), viewer, inputTriggerConfig ); - BigDataViewerActions.installActionBindings( viewerFrame.getKeybindings(), this, inputTriggerConfig ); - - final JMenuBar menubar = new JMenuBar(); - JMenu menu = new JMenu( "File" ); - menubar.add( menu ); - - final ActionMap actionMap = viewerFrame.getKeybindings().getConcatenatedActionMap(); - final JMenuItem miLoadSettings = new JMenuItem( actionMap.get( BigDataViewerActions.LOAD_SETTINGS ) ); - miLoadSettings.setText( "Load settings" ); - menu.add( miLoadSettings ); - - final JMenuItem miSaveSettings = new JMenuItem( actionMap.get( BigDataViewerActions.SAVE_SETTINGS ) ); - miSaveSettings.setText( "Save settings" ); - menu.add( miSaveSettings ); - - menu = new JMenu( "Settings" ); - menubar.add( menu ); - - final JMenuItem miBrightness = new JMenuItem( actionMap.get( BigDataViewerActions.BRIGHTNESS_SETTINGS ) ); - miBrightness.setText( "Brightness & Color" ); - menu.add( miBrightness ); - - final JMenuItem miVisibility = new JMenuItem( actionMap.get( BigDataViewerActions.VISIBILITY_AND_GROUPING ) ); - miVisibility.setText( "Visibility & Grouping" ); - menu.add( miVisibility ); - - menu = new JMenu( "Tools" ); - menubar.add( menu ); - - if ( cropDialog != null ) - { - final JMenuItem miCrop = new JMenuItem( actionMap.get( BigDataViewerActions.CROP ) ); - miCrop.setText( "Crop" ); - menu.add( miCrop ); - } - - final JMenuItem miMovie = new JMenuItem( actionMap.get( BigDataViewerActions.RECORD_MOVIE ) ); - miMovie.setText( "Record Movie" ); - menu.add( miMovie ); - - final JMenuItem miMaxProjectMovie = new JMenuItem( actionMap.get( BigDataViewerActions.RECORD_MAX_PROJECTION_MOVIE ) ); - miMaxProjectMovie.setText( "Record Max-Projection Movie" ); - menu.add( miMaxProjectMovie ); - - final JMenuItem miManualTransform = new JMenuItem( actionMap.get( BigDataViewerActions.MANUAL_TRANSFORM ) ); - miManualTransform.setText( "Manual Transform" ); - menu.add( miManualTransform ); - - menu = new JMenu( "Help" ); - menubar.add( menu ); - - final JMenuItem miHelp = new JMenuItem( actionMap.get( BigDataViewerActions.SHOW_HELP ) ); - miHelp.setText( "Show Help" ); - menu.add( miHelp ); - - viewerFrame.setJMenuBar( menubar ); - } - - public static BigDataViewer open( final AbstractSpimData< ? > spimData, final String windowTitle, final ProgressWriter progressWriter, final ViewerOptions options ) - { - if ( WrapBasicImgLoader.wrapImgLoaderIfNecessary( spimData ) ) - { - System.err.println( "WARNING:\nOpening <SpimData> dataset that is not suited for interactive browsing.\nConsider resaving as HDF5 for better performance." ); - } - - final ArrayList< ConverterSetup > converterSetups = new ArrayList<>(); - final ArrayList< SourceAndConverter< ? > > sources = new ArrayList<>(); - initSetups( spimData, converterSetups, sources ); - - final AbstractSequenceDescription< ?, ?, ? > seq = spimData.getSequenceDescription(); - final int numTimepoints = seq.getTimePoints().size(); - final CacheControl cache = ( ( ViewerImgLoader ) seq.getImgLoader() ).getCacheControl(); - - final BigDataViewer bdv = new BigDataViewer( converterSetups, sources, spimData, numTimepoints, cache, windowTitle, progressWriter, options ); - - WrapBasicImgLoader.removeWrapperIfPresent( spimData ); - - bdv.viewerFrame.setVisible( true ); - InitializeViewerState.initTransform( bdv.viewer ); - return bdv; - } + protected final BrightnessDialog brightnessDialog; - public static BigDataViewer open(final String xmlFilename, + protected final RecordMaxProjectionDialog movieMaxProjectDialog; + + protected final VisibilityAndGroupingDialog activeSourcesDialog; + + protected final HelpDialog helpDialog; + + protected final ManualTransformationEditor manualTransformationEditor; + + protected final BookmarksEditor bookmarkEditor; + + protected final JFileChooser fileChooser; + + protected File proposedSettingsFile; + + private boolean enableCompression; + + public void toggleManualTransformation() { + manualTransformationEditor.toggle(); + } + + public void initSetBookmark() { + bookmarkEditor.initSetBookmark(); + } + + public void initGoToBookmark() { + bookmarkEditor.initGoToBookmark(); + } + + public void initGoToBookmarkRotation() { + bookmarkEditor.initGoToBookmarkRotation(); + } + + private static String createSetupName(final BasicViewSetup setup) { + if (setup.hasName()) + return setup.getName(); + + String name = ""; + + final Angle angle = setup.getAttribute(Angle.class); + if (angle != null) + name += (name.isEmpty() ? "" : " ") + "a " + angle.getName(); + + final Channel channel = setup.getAttribute(Channel.class); + if (channel != null) + name += (name.isEmpty() ? "" : " ") + "c " + channel.getName(); + + return name; + } + + /** + * Create standard converter from the given {@code type} to ARGB: + * <ul> + * <li>For {@code RealType}s a {@link RealARGBColorConverter} is + * returned.</li> + * <li>For {@code ARGBType}s a {@link ScaledARGBConverter.ARGB} is + * returned.</li> + * <li>For {@code VolatileARGBType}s a + * {@link ScaledARGBConverter.VolatileARGB} is returned.</li> + * </ul> + */ + @SuppressWarnings("unchecked") + public static <T extends NumericType<T>> Converter<T, ARGBType> createConverterToARGB(final T type) { + if (type instanceof RealType) { + final RealType<?> t = (RealType<?>) type; + final double typeMin = Math.max(0, Math.min(t.getMinValue(), 65535)); + final double typeMax = Math.max(0, Math.min(t.getMaxValue(), 65535)); + return (Converter<T, ARGBType>) RealARGBColorConverter.create(t, typeMin, typeMax); + } else if (type instanceof ARGBType) + return (Converter<T, ARGBType>) new ScaledARGBConverter.ARGB(0, 255); + else if (type instanceof VolatileARGBType) + return (Converter<T, ARGBType>) new ScaledARGBConverter.VolatileARGB(0, 255); + else + throw new IllegalArgumentException("ImgLoader of type " + type.getClass() + " not supported."); + } + + /** + * Create a {@code ConverterSetup} for the given {@code SourceAndConverter}. + * {@link SourceAndConverter#asVolatile() Nested volatile} + * {@code SourceAndConverter} are added to the {@code ConverterSetup} if + * present. If {@code SourceAndConverter} does not comprise a + * {@code ColorConverter}, returns {@code null}. + * + * @param soc {@code SourceAndConverter} for which to create a + * {@code ConverterSetup} + * @param setupId setupId of the created {@code ConverterSetup} + * @return a new {@code ConverterSetup} or {@code null} + */ + public static ConverterSetup createConverterSetup(final SourceAndConverter<?> soc, final int setupId) { + final List<ColorConverter> converters = new ArrayList<>(); + + final Converter<?, ARGBType> c = soc.getConverter(); + if (c instanceof ColorConverter) + converters.add((ColorConverter) c); + + final SourceAndConverter<? extends Volatile<?>> vsoc = soc.asVolatile(); + if (vsoc != null) { + final Converter<?, ARGBType> vc = vsoc.getConverter(); + if (vc instanceof ColorConverter) + converters.add((ColorConverter) vc); + } + + if (converters.isEmpty()) + return null; + else + return new RealARGBColorConverterSetup(setupId, converters); + } + + /** + * Decorate source with an extra transformation, that can be edited manually + * in this viewer. {@link SourceAndConverter#asVolatile() Nested volatile} + * {@code SourceAndConverter} are wrapped as well, if present. + */ + public static <T, V extends Volatile<T>> SourceAndConverter<T> wrapWithTransformedSource(final SourceAndConverter<T> soc) { + if (soc.asVolatile() == null) + return new SourceAndConverter<>(new TransformedSource<>(soc.getSpimSource()), soc.getConverter()); + + @SuppressWarnings("unchecked") final SourceAndConverter<V> vsoc = (SourceAndConverter<V>) soc.asVolatile(); + final TransformedSource<T> ts = new TransformedSource<>(soc.getSpimSource()); + final TransformedSource<V> vts = new TransformedSource<>(vsoc.getSpimSource(), ts); + return new SourceAndConverter<>(ts, soc.getConverter(), new SourceAndConverter<>(vts, vsoc.getConverter())); + } + + private static <T extends NumericType<T>, V extends Volatile<T> & NumericType<V>> void initSetupNumericType( + final AbstractSpimData<?> spimData, + final BasicViewSetup setup, + final List<ConverterSetup> converterSetups, + final List<SourceAndConverter<?>> sources) { + final int setupId = setup.getId(); + final ViewerImgLoader imgLoader = (ViewerImgLoader) spimData.getSequenceDescription().getImgLoader(); + @SuppressWarnings("unchecked") final ViewerSetupImgLoader<T, V> setupImgLoader = + (ViewerSetupImgLoader<T, V>) imgLoader.getSetupImgLoader( + setupId); + final T type = setupImgLoader.getImageType(); + final V volatileType = setupImgLoader.getVolatileImageType(); + + if (!(type instanceof NumericType)) + throw new IllegalArgumentException("ImgLoader of type " + type.getClass() + " not supported."); + + final String setupName = createSetupName(setup); + + SourceAndConverter<V> vsoc = null; + if (volatileType != null) { + final VolatileSpimSource<V> vs = new VolatileSpimSource<>(spimData, setupId, setupName); + vsoc = new SourceAndConverter<>(vs, createConverterToARGB(volatileType)); + } + + final SpimSource<T> s = new SpimSource<>(spimData, setupId, setupName); + final SourceAndConverter<T> soc = new SourceAndConverter<>(s, createConverterToARGB(type), vsoc); + final SourceAndConverter<T> tsoc = wrapWithTransformedSource(soc); + sources.add(tsoc); + + final ConverterSetup converterSetup = createConverterSetup(tsoc, setupId); + if (converterSetup != null) + converterSetups.add(converterSetup); + } + + public static void initSetups( + final AbstractSpimData<?> spimData, + final List<ConverterSetup> converterSetups, + final List<SourceAndConverter<?>> sources) { + for (final BasicViewSetup setup : spimData.getSequenceDescription().getViewSetupsOrdered()) + initSetupNumericType(spimData, setup, converterSetups, sources); + } + + /** + * @param converterSetups list of {@link ConverterSetup} that control min/max and color + * of sources. + * @param sources list of pairs of source of some type and converter from that + * type to ARGB. + * @param spimData may be null. The {@link AbstractSpimData} of the dataset (if + * there is one). If it exists, it is used to set up a "Crop" + * dialog. + * @param numTimepoints the number of timepoints in the dataset. + * @param cache handle to cache. This is used to control io timing. + * @param windowTitle title of the viewer window. + * @param progressWriter a {@link ProgressWriter} to which BDV may report progress + * (currently only used in the "Record Movie" dialog). + * @param options optional parameters. + */ + public BigDataViewer( + final ArrayList<ConverterSetup> converterSetups, + final ArrayList<SourceAndConverter<?>> sources, + final AbstractSpimData<?> spimData, + final int numTimepoints, + final CacheControl cache, + final String windowTitle, + final ProgressWriter progressWriter, + final ViewerOptions options) { + final InputTriggerConfig inputTriggerConfig = getInputTriggerConfig(options); + + viewerFrame = new ViewerFrame(sources, numTimepoints, cache, options.inputTriggerConfig(inputTriggerConfig)); + if (windowTitle != null) + viewerFrame.setTitle(windowTitle); + viewer = viewerFrame.getViewerPanel(); + + // final ConverterSetup.SetupChangeListener requestRepaint = s -> viewer.requestRepaint(); + // for ( final ConverterSetup cs : converterSetups ) + // cs.setupChangeListeners().add( requestRepaint ); + + manualTransformation = new ManualTransformation(viewer); + manualTransformationEditor = new ManualTransformationEditor(viewer, viewerFrame.getKeybindings()); + + bookmarks = new Bookmarks(); + bookmarkEditor = new BookmarksEditor(viewer, viewerFrame.getKeybindings(), bookmarks); + + final ConverterSetups setups = viewerFrame.getConverterSetups(); + if (converterSetups.size() != sources.size()) + System.err.println("WARNING! Constructing BigDataViewer, with converterSetups.size() that is not the same as sources.size()."); + final int numSetups = Math.min(converterSetups.size(), sources.size()); + for (int i = 0; i < numSetups; ++i) { + final SourceAndConverter<?> source = sources.get(i); + final ConverterSetup setup = converterSetups.get(i); + if (setup != null) + setups.put(source, setup); + } + + setupAssignments = new SetupAssignments(converterSetups, 0, 65535); + if (setupAssignments.getMinMaxGroups().size() > 0) { + final MinMaxGroup group = setupAssignments.getMinMaxGroups().get(0); + for (final ConverterSetup setup : setupAssignments.getConverterSetups()) + setupAssignments.moveSetupToGroup(setup, group); + } + + brightnessDialog = new BrightnessDialog(viewerFrame, setupAssignments); + + if (spimData != null) + viewer.getSourceInfoOverlayRenderer().setTimePointsOrdered(spimData.getSequenceDescription().getTimePoints().getTimePointsOrdered()); + + cropDialog = (spimData == null) ? null : new CropDialog(viewerFrame, viewer, spimData.getSequenceDescription()); + + movieDialog = new RecordMovieDialog(viewerFrame, viewer, progressWriter); + // this is just to get updates of window size: + viewer.getDisplay().overlays().add(movieDialog); + + movieMaxProjectDialog = new RecordMaxProjectionDialog(viewerFrame, viewer, progressWriter); + // this is just to get updates of window size: + viewer.getDisplay().overlays().add(movieMaxProjectDialog); + + activeSourcesDialog = new VisibilityAndGroupingDialog(viewerFrame, viewer.state()); + + helpDialog = new HelpDialog(viewerFrame); + + fileChooser = new JFileChooser(); + fileChooser.setFileFilter(new FileFilter() { + @Override + public String getDescription() { + return "xml files"; + } + + @Override + public boolean accept(final File f) { + if (f.isDirectory()) + return true; + if (f.isFile()) { + final String s = f.getName(); + final int i = s.lastIndexOf('.'); + if (i > 0 && i < s.length() - 1) { + final String ext = s.substring(i + 1).toLowerCase(); + return ext.equals("xml"); + } + } + return false; + } + }); + + NavigationActions.installActionBindings(viewerFrame.getKeybindings(), viewer, inputTriggerConfig); + BigDataViewerActions.installActionBindings(viewerFrame.getKeybindings(), this, inputTriggerConfig); + + final JMenuBar menubar = new JMenuBar(); + JMenu menu = new JMenu("File"); + menubar.add(menu); + + final ActionMap actionMap = viewerFrame.getKeybindings().getConcatenatedActionMap(); + final JMenuItem miLoadSettings = new JMenuItem(actionMap.get(BigDataViewerActions.LOAD_SETTINGS)); + miLoadSettings.setText("Load settings"); + menu.add(miLoadSettings); + + final JMenuItem miSaveSettings = new JMenuItem(actionMap.get(BigDataViewerActions.SAVE_SETTINGS)); + miSaveSettings.setText("Save settings"); + menu.add(miSaveSettings); + + menu = new JMenu("Settings"); + menubar.add(menu); + + final JMenuItem miBrightness = new JMenuItem(actionMap.get(BigDataViewerActions.BRIGHTNESS_SETTINGS)); + miBrightness.setText("Brightness & Color"); + menu.add(miBrightness); + + final JMenuItem miVisibility = new JMenuItem(actionMap.get(BigDataViewerActions.VISIBILITY_AND_GROUPING)); + miVisibility.setText("Visibility & Grouping"); + menu.add(miVisibility); + + menu = new JMenu("Tools"); + menubar.add(menu); + + if (cropDialog != null) { + final JMenuItem miCrop = new JMenuItem(actionMap.get(BigDataViewerActions.CROP)); + miCrop.setText("Crop"); + menu.add(miCrop); + } + + final JMenuItem miMovie = new JMenuItem(actionMap.get(BigDataViewerActions.RECORD_MOVIE)); + miMovie.setText("Record Movie"); + menu.add(miMovie); + + final JMenuItem miMaxProjectMovie = new JMenuItem(actionMap.get(BigDataViewerActions.RECORD_MAX_PROJECTION_MOVIE)); + miMaxProjectMovie.setText("Record Max-Projection Movie"); + menu.add(miMaxProjectMovie); + + final JMenuItem miManualTransform = new JMenuItem(actionMap.get(BigDataViewerActions.MANUAL_TRANSFORM)); + miManualTransform.setText("Manual Transform"); + menu.add(miManualTransform); + + enableCompression = options.values.getCompressionOptions().isEnabled(); + if (options.values.getCompressionOptions().isEnabled()) { + menu = new JMenu("QCMP Compression"); + menubar.add(menu); + + final JCheckBoxMenuItem enableCompressionCheckBox = new JCheckBoxMenuItem("Enable compression", true); + enableCompressionCheckBox.addActionListener(e -> { + enableDisableCompression(enableCompressionCheckBox.isSelected()); + }); + + menu.add(enableCompressionCheckBox); + } + + + menu = new JMenu("Help"); + menubar.add(menu); + + final JMenuItem miHelp = new JMenuItem(actionMap.get(BigDataViewerActions.SHOW_HELP)); + miHelp.setText("Show Help"); + menu.add(miHelp); + + + viewerFrame.setJMenuBar(menubar); + } + + public static BigDataViewer open(final AbstractSpimData<?> spimData, final String windowTitle, final ProgressWriter progressWriter, - final ViewerOptions options, - final ViewerCompressionOptions ops) throws SpimDataException { + final ViewerOptions options) { + if (WrapBasicImgLoader.wrapImgLoaderIfNecessary(spimData)) { + System.err.println( + "WARNING:\nOpening <SpimData> dataset that is not suited for interactive browsing.\nConsider resaving as HDF5 for " + + "better performance."); + } + + final ArrayList<ConverterSetup> converterSetups = new ArrayList<>(); + final ArrayList<SourceAndConverter<?>> sources = new ArrayList<>(); + initSetups(spimData, converterSetups, sources); + + final AbstractSequenceDescription<?, ?, ?> seq = spimData.getSequenceDescription(); + final int numTimepoints = seq.getTimePoints().size(); + final CacheControl cache = ((ViewerImgLoader) seq.getImgLoader()).getCacheControl(); + + final BigDataViewer bdv = new BigDataViewer(converterSetups, + sources, + spimData, + numTimepoints, + cache, + windowTitle, + progressWriter, + options); + + WrapBasicImgLoader.removeWrapperIfPresent(spimData); + + bdv.viewerFrame.setVisible(true); + InitializeViewerState.initTransform(bdv.viewer); + return bdv; + } + + private synchronized void enableDisableCompression(final boolean enabled) { + if (this.enableCompression == enabled) + return; + this.enableCompression = enabled; + + + } + public static BigDataViewer open(final String xmlFilename, + final String windowTitle, + final ProgressWriter progressWriter, + final ViewerOptions options) throws SpimDataException { final XmlIoSpimDataMinimal xmlIoSpimDataMinimal = new XmlIoSpimDataMinimal(); - xmlIoSpimDataMinimal.setViewerCompressionOptions(ops); + xmlIoSpimDataMinimal.setViewerCompressionOptions(options.values.getCompressionOptions()); + final SpimDataMinimal spimData = xmlIoSpimDataMinimal.load(xmlFilename); final BigDataViewer bdv = open(spimData, windowTitle, progressWriter, options); if (!bdv.tryLoadSettings(xmlFilename)) - InitializeViewerState.initBrightness( 0.001, 0.999, bdv.viewerFrame ); + InitializeViewerState.initBrightness(0.001, 0.999, bdv.viewerFrame); return bdv; } - public static BigDataViewer open( final String xmlFilename, final String windowTitle, final ProgressWriter progressWriter, final ViewerOptions options ) throws SpimDataException - { - final SpimDataMinimal spimData = new XmlIoSpimDataMinimal().load( xmlFilename ); - final BigDataViewer bdv = open( spimData, windowTitle, progressWriter, options ); - if ( !bdv.tryLoadSettings( xmlFilename ) ) - InitializeViewerState.initBrightness( 0.001, 0.999, bdv.viewerFrame ); - return bdv; - } - - public static BigDataViewer open( - final ArrayList< ConverterSetup > converterSetups, - final ArrayList< SourceAndConverter< ? > > sources, - final int numTimepoints, - final CacheControl cache, - final String windowTitle, - final ProgressWriter progressWriter, - final ViewerOptions options ) - { - final BigDataViewer bdv = new BigDataViewer( converterSetups, sources, null, numTimepoints, cache, windowTitle, progressWriter, options ); - bdv.viewerFrame.setVisible( true ); - InitializeViewerState.initTransform( bdv.viewer ); - return bdv; - } - - public ViewerPanel getViewer() - { - return viewer; - } - - public ViewerFrame getViewerFrame() - { - return viewerFrame; - } - - public ConverterSetups getConverterSetups() - { - return viewerFrame.getConverterSetups(); - } - - /** - * @deprecated Instead {@code getViewer().state()} returns the {@link ViewerState} that can be modified directly. - */ - @Deprecated - public SetupAssignments getSetupAssignments() - { - return setupAssignments; - } - - public ManualTransformationEditor getManualTransformEditor() - { - return manualTransformationEditor; - } - - public boolean tryLoadSettings( final String xmlFilename ) - { - proposedSettingsFile = null; - if( xmlFilename.startsWith( "http://" ) ) - { - // load settings.xml from the BigDataServer - final String settings = xmlFilename + "settings"; - { - try - { - loadSettings( settings ); - return true; - } - catch ( final FileNotFoundException e ) - {} - catch ( final Exception e ) - { - e.printStackTrace(); - } - } - } - else if ( xmlFilename.endsWith( ".xml" ) ) - { - final String settings = xmlFilename.substring( 0, xmlFilename.length() - ".xml".length() ) + ".settings" + ".xml"; - proposedSettingsFile = new File( settings ); - if ( proposedSettingsFile.isFile() ) - { - try - { - loadSettings( settings ); - return true; - } - catch ( final Exception e ) - { - e.printStackTrace(); - } - } - } - return false; - } - - public void saveSettings() - { - fileChooser.setSelectedFile( proposedSettingsFile ); - final int returnVal = fileChooser.showSaveDialog( null ); - if ( returnVal == JFileChooser.APPROVE_OPTION ) - { - proposedSettingsFile = fileChooser.getSelectedFile(); - try - { - saveSettings( proposedSettingsFile.getCanonicalPath() ); - } - catch ( final IOException e ) - { - e.printStackTrace(); - } - } - } - - public void saveSettings( final String xmlFilename ) throws IOException - { - final Element root = new Element( "Settings" ); - root.addContent( viewer.stateToXml() ); - root.addContent( setupAssignments.toXml() ); - root.addContent( manualTransformation.toXml() ); - root.addContent( bookmarks.toXml() ); - final Document doc = new Document( root ); - final XMLOutputter xout = new XMLOutputter( Format.getPrettyFormat() ); - xout.output( doc, new FileWriter( xmlFilename ) ); - } - - /** - * If {@code options} doesn't define a {@link InputTriggerConfig}, try to - * load it from files in this order: - * <ol> - * <li>"bdvkeyconfig.yaml" in the current directory. - * <li>".bdv/bdvkeyconfig.yaml" in the user's home directory. - * <li>legacy "bigdataviewer.keys.properties" in current directory (will be - * also written to "bdvkeyconfig.yaml"). - * </ol> - * - * @param options - * @return - */ - public static InputTriggerConfig getInputTriggerConfig( final ViewerOptions options ) - { - InputTriggerConfig conf = options.values.getInputTriggerConfig(); - - // try "bdvkeyconfig.yaml" in current directory - if ( conf == null && new File( "bdvkeyconfig.yaml" ).isFile() ) - { - try - { - conf = new InputTriggerConfig( YamlConfigIO.read( "bdvkeyconfig.yaml" ) ); - } - catch ( final IOException e ) - {} - } - - // try "~/.bdv/bdvkeyconfig.yaml" - if ( conf == null ) - { - final String fn = System.getProperty( "user.home" ) + "/.bdv/bdvkeyconfig.yaml"; - if ( new File( fn ).isFile() ) - { - try - { - conf = new InputTriggerConfig( YamlConfigIO.read( fn ) ); - } - catch ( final IOException e ) - {} - } - } - - if ( conf == null ) - { - conf = new InputTriggerConfig(); - } - - return conf; - } - - public void loadSettings() - { - fileChooser.setSelectedFile( proposedSettingsFile ); - final int returnVal = fileChooser.showOpenDialog( null ); - if ( returnVal == JFileChooser.APPROVE_OPTION ) - { - proposedSettingsFile = fileChooser.getSelectedFile(); - try - { - loadSettings( proposedSettingsFile.getCanonicalPath() ); - } - catch ( final Exception e ) - { - e.printStackTrace(); - } - } - } - - public void loadSettings( final String xmlFilename ) throws IOException, JDOMException - { - final SAXBuilder sax = new SAXBuilder(); - final Document doc = sax.build( xmlFilename ); - final Element root = doc.getRootElement(); - viewer.stateFromXml( root ); - setupAssignments.restoreFromXml( root ); - manualTransformation.restoreFromXml( root ); - bookmarks.restoreFromXml( root ); - activeSourcesDialog.update(); - viewer.requestRepaint(); - } - - public void expandAndFocusCardPanel() - { - viewerFrame.getSplitPanel().setCollapsed( false ); - viewerFrame.getSplitPanel().getRightComponent().requestFocusInWindow(); - } - - public void collapseCardPanel() - { - viewerFrame.getSplitPanel().setCollapsed( true ); - viewer.requestFocusInWindow(); - } + public static BigDataViewer open( + final ArrayList<ConverterSetup> converterSetups, + final ArrayList<SourceAndConverter<?>> sources, + final int numTimepoints, + final CacheControl cache, + final String windowTitle, + final ProgressWriter progressWriter, + final ViewerOptions options) { + final BigDataViewer bdv = new BigDataViewer(converterSetups, + sources, + null, + numTimepoints, + cache, + windowTitle, + progressWriter, + options); + bdv.viewerFrame.setVisible(true); + InitializeViewerState.initTransform(bdv.viewer); + return bdv; + } + + public ViewerPanel getViewer() { + return viewer; + } + + public ViewerFrame getViewerFrame() { + return viewerFrame; + } + + public ConverterSetups getConverterSetups() { + return viewerFrame.getConverterSetups(); + } + + /** + * @deprecated Instead {@code getViewer().state()} returns the {@link ViewerState} that can be modified directly. + */ + @Deprecated + public SetupAssignments getSetupAssignments() { + return setupAssignments; + } + + public ManualTransformationEditor getManualTransformEditor() { + return manualTransformationEditor; + } + + public boolean tryLoadSettings(final String xmlFilename) { + proposedSettingsFile = null; + if (xmlFilename.startsWith("http://")) { + // load settings.xml from the BigDataServer + final String settings = xmlFilename + "settings"; + { + try { + loadSettings(settings); + return true; + } catch (final FileNotFoundException e) { + } catch (final Exception e) { + e.printStackTrace(); + } + } + } else if (xmlFilename.endsWith(".xml")) { + final String settings = xmlFilename.substring(0, xmlFilename.length() - ".xml".length()) + ".settings" + ".xml"; + proposedSettingsFile = new File(settings); + if (proposedSettingsFile.isFile()) { + try { + loadSettings(settings); + return true; + } catch (final Exception e) { + e.printStackTrace(); + } + } + } + return false; + } + + public void saveSettings() { + fileChooser.setSelectedFile(proposedSettingsFile); + final int returnVal = fileChooser.showSaveDialog(null); + if (returnVal == JFileChooser.APPROVE_OPTION) { + proposedSettingsFile = fileChooser.getSelectedFile(); + try { + saveSettings(proposedSettingsFile.getCanonicalPath()); + } catch (final IOException e) { + e.printStackTrace(); + } + } + } + + public void saveSettings(final String xmlFilename) throws IOException { + final Element root = new Element("Settings"); + root.addContent(viewer.stateToXml()); + root.addContent(setupAssignments.toXml()); + root.addContent(manualTransformation.toXml()); + root.addContent(bookmarks.toXml()); + final Document doc = new Document(root); + final XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat()); + xout.output(doc, new FileWriter(xmlFilename)); + } + + /** + * If {@code options} doesn't define a {@link InputTriggerConfig}, try to + * load it from files in this order: + * <ol> + * <li>"bdvkeyconfig.yaml" in the current directory. + * <li>".bdv/bdvkeyconfig.yaml" in the user's home directory. + * <li>legacy "bigdataviewer.keys.properties" in current directory (will be + * also written to "bdvkeyconfig.yaml"). + * </ol> + * + * @param options + * @return + */ + public static InputTriggerConfig getInputTriggerConfig(final ViewerOptions options) { + InputTriggerConfig conf = options.values.getInputTriggerConfig(); + + // try "bdvkeyconfig.yaml" in current directory + if (conf == null && new File("bdvkeyconfig.yaml").isFile()) { + try { + conf = new InputTriggerConfig(YamlConfigIO.read("bdvkeyconfig.yaml")); + } catch (final IOException e) { + } + } + + // try "~/.bdv/bdvkeyconfig.yaml" + if (conf == null) { + final String fn = System.getProperty("user.home") + "/.bdv/bdvkeyconfig.yaml"; + if (new File(fn).isFile()) { + try { + conf = new InputTriggerConfig(YamlConfigIO.read(fn)); + } catch (final IOException e) { + } + } + } + + if (conf == null) { + conf = new InputTriggerConfig(); + } + + return conf; + } + + public void loadSettings() { + fileChooser.setSelectedFile(proposedSettingsFile); + final int returnVal = fileChooser.showOpenDialog(null); + if (returnVal == JFileChooser.APPROVE_OPTION) { + proposedSettingsFile = fileChooser.getSelectedFile(); + try { + loadSettings(proposedSettingsFile.getCanonicalPath()); + } catch (final Exception e) { + e.printStackTrace(); + } + } + } + + public void loadSettings(final String xmlFilename) throws IOException, JDOMException { + final SAXBuilder sax = new SAXBuilder(); + final Document doc = sax.build(xmlFilename); + final Element root = doc.getRootElement(); + viewer.stateFromXml(root); + setupAssignments.restoreFromXml(root); + manualTransformation.restoreFromXml(root); + bookmarks.restoreFromXml(root); + activeSourcesDialog.update(); + viewer.requestRepaint(); + } + + public void expandAndFocusCardPanel() { + viewerFrame.getSplitPanel().setCollapsed(false); + viewerFrame.getSplitPanel().getRightComponent().requestFocusInWindow(); + } + + public void collapseCardPanel() { + viewerFrame.getSplitPanel().setCollapsed(true); + viewer.requestFocusInWindow(); + } public static void main(final String[] args) { if (args.length < 1) { @@ -714,29 +670,22 @@ public class BigDataViewer { } final String fn = args[0]; - final ViewerCompressionOptions ops = new ViewerCompressionOptions(); + final ViewerOptions viewerOptions = ViewerOptions.options(); if (args.length > 1) { for (int i = 1; i < args.length; i++) { switch (args[i]) { case "-qcmp": - ops.setEnabled(true); - break; - case "-compress-from": - if (args.length <= i + 1) { - System.err.println("Missing -compress-from integer parameter."); - return; - } - ops.setCompressFromMipmapLevel(Integer.parseInt(args[++i])); + viewerOptions.values.getCompressionOptions().setEnabled(true); break; } } } - ColorConsole.printf(ColorConsole.Color.Green, "Compression:\t" + (ops.isEnabled() ? "ON" : "OFF")); - if (ops.isEnabled()) - ColorConsole.printf(ColorConsole.Color.Green, "CompressFrom:\t" + ops.getCompressFromMipmapLevel()); + ColorConsole.printf(ColorConsole.Color.Green, "Compression:\t" + + (viewerOptions.values.getCompressionOptions().isEnabled() ? "ON" : "OFF")); + try { System.setProperty("apple.laf.useScreenMenuBar", "true"); @@ -744,8 +693,7 @@ public class BigDataViewer { final BigDataViewer bdv = open(fn, "Server test", new ProgressWriterConsole(), - ViewerOptions.options(), - ops); + viewerOptions); } catch (final Exception e) { e.printStackTrace(); diff --git a/src/main/java/bdv/img/remote/RemoteImageLoader.java b/src/main/java/bdv/img/remote/RemoteImageLoader.java index 01835d7790c86af1b55466e22a035fd41c4964cc..74178125e057eb7c88ec721b2cb5209057873afc 100644 --- a/src/main/java/bdv/img/remote/RemoteImageLoader.java +++ b/src/main/java/bdv/img/remote/RemoteImageLoader.java @@ -28,7 +28,6 @@ */ package bdv.img.remote; -import azgracompress.ViewerCompressionOptions; import azgracompress.cache.ICacheFile; import azgracompress.cache.QuantizationCacheManager; import azgracompress.compression.ImageDecompressor; @@ -41,6 +40,7 @@ import bdv.img.hdf5.DimsAndExistence; import bdv.img.hdf5.MipmapInfo; import bdv.img.hdf5.ViewLevelId; import bdv.util.ConstantRandomAccessible; +import bdv.viewer.ViewerOptions; import com.google.gson.GsonBuilder; import mpicbg.spim.data.generic.sequence.ImgLoaderHint; import net.imglib2.FinalInterval; @@ -77,7 +77,7 @@ public class RemoteImageLoader implements ViewerImgLoader { /** * Flag whether we allow the server to send us compressed data. */ - private ViewerCompressionOptions viewerCompressionOptions; + private ViewerOptions.CompressionOptions viewerCompressionOptions; /** @@ -131,7 +131,7 @@ public class RemoteImageLoader implements ViewerImgLoader { } } - public void setViewerCompressionOptions(final ViewerCompressionOptions ops) { + public void setViewerCompressionOptions(final ViewerOptions.CompressionOptions ops) { this.viewerCompressionOptions = ops; } @@ -146,7 +146,9 @@ public class RemoteImageLoader implements ViewerImgLoader { return; } final ArrayList<ICacheFile> cacheFiles = new ArrayList<>(); + int compressFromMipmapLevel = 0; try (final DataInputStream dis = new DataInputStream(connection.getInputStream())) { + compressFromMipmapLevel = dis.readByte(); final int codebookCount = dis.readByte(); for (int cbIndex = 0; cbIndex < codebookCount; cbIndex++) { final ICacheFile readCacheFile = QuantizationCacheManager.readCacheFile(dis); @@ -160,13 +162,15 @@ public class RemoteImageLoader implements ViewerImgLoader { } } ColorConsole.fprintf(ColorConsole.Target.stdout, ColorConsole.Color.Yellow, "Received %d cache files.", cacheFiles.size()); + ColorConsole.fprintf(ColorConsole.Target.stdout, ColorConsole.Color.Yellow, + "Decompressing from mipmap level %d.", compressFromMipmapLevel); final ImageDecompressor[] decompressors = new ImageDecompressor[cacheFiles.size()]; for (int i = 0; i < cacheFiles.size(); i++) { decompressors[i] = new ImageDecompressor(cacheFiles.get(i)); } - shortLoader.setDataDecompressors(decompressors, metadata.maxNumLevels, viewerCompressionOptions.getCompressFromMipmapLevel()); + shortLoader.setDataDecompressors(decompressors, metadata.maxNumLevels, compressFromMipmapLevel); } diff --git a/src/main/java/bdv/spimdata/XmlIoSpimDataMinimal.java b/src/main/java/bdv/spimdata/XmlIoSpimDataMinimal.java index 2d5daf3cb1bde2824b930c8d4f23f52438f5b5d9..a2baab0cac95f8e82215d1e8b322790cf7e4c9e1 100644 --- a/src/main/java/bdv/spimdata/XmlIoSpimDataMinimal.java +++ b/src/main/java/bdv/spimdata/XmlIoSpimDataMinimal.java @@ -28,9 +28,9 @@ */ package bdv.spimdata; -import azgracompress.ViewerCompressionOptions; import bdv.img.remote.RemoteImageLoader; import bdv.spimdata.legacy.XmlIoSpimDataMinimalLegacy; +import bdv.viewer.ViewerOptions; import mpicbg.spim.data.SpimDataException; import mpicbg.spim.data.SpimDataIOException; import mpicbg.spim.data.generic.XmlIoAbstractSpimData; @@ -49,7 +49,7 @@ import java.io.File; import static mpicbg.spim.data.XmlKeys.SPIMDATA_TAG; public class XmlIoSpimDataMinimal extends XmlIoAbstractSpimData<SequenceDescriptionMinimal, SpimDataMinimal> { - private ViewerCompressionOptions compressionOptions; + private ViewerOptions.CompressionOptions compressionOptions; public XmlIoSpimDataMinimal() { super(SpimDataMinimal.class, @@ -61,7 +61,7 @@ public class XmlIoSpimDataMinimal extends XmlIoAbstractSpimData<SequenceDescript new XmlIoViewRegistrations()); } - public void setViewerCompressionOptions(final ViewerCompressionOptions ops) { + public void setViewerCompressionOptions(final ViewerOptions.CompressionOptions ops) { this.compressionOptions = ops; } diff --git a/src/main/java/bdv/viewer/ViewerOptions.java b/src/main/java/bdv/viewer/ViewerOptions.java index b977c4585e8fdfadafe7b32ffc2efb6bb0a283f4..9561384d069cdcdd6ff0fb5265a08435ba3c6899 100644 --- a/src/main/java/bdv/viewer/ViewerOptions.java +++ b/src/main/java/bdv/viewer/ViewerOptions.java @@ -6,13 +6,13 @@ * %% * 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 @@ -29,285 +29,274 @@ package bdv.viewer; import bdv.TransformEventHandler3D; -import java.awt.event.KeyListener; - -import org.scijava.ui.behaviour.KeyPressedManager; -import org.scijava.ui.behaviour.io.InputTriggerConfig; - +import bdv.TransformEventHandlerFactory; import bdv.viewer.animate.MessageOverlayAnimator; import bdv.viewer.render.AccumulateProjector; import bdv.viewer.render.AccumulateProjectorARGB; import bdv.viewer.render.AccumulateProjectorFactory; import bdv.viewer.render.MultiResolutionRenderer; -import net.imglib2.realtransform.AffineTransform3D; import net.imglib2.type.numeric.ARGBType; -import bdv.TransformEventHandlerFactory; +import org.scijava.ui.behaviour.KeyPressedManager; +import org.scijava.ui.behaviour.io.InputTriggerConfig; + +import java.awt.event.KeyListener; /** * Optional parameters for {@link ViewerPanel}. * * @author Tobias Pietzsch */ -public class ViewerOptions -{ - public final Values values = new Values(); - - /** - * Create default {@link ViewerOptions}. - * @return default {@link ViewerOptions}. - */ - public static ViewerOptions options() - { - return new ViewerOptions(); - } - - /** - * Set width of {@link ViewerPanel} canvas. - */ - public ViewerOptions width( final int w ) - { - values.width = w; - return this; - } - - /** - * Set height of {@link ViewerPanel} canvas. - */ - public ViewerOptions height( final int h ) - { - values.height = h; - return this; - } - - /** - * Set the number and scale factors for scaled screen images. - * - * @param s - * Scale factors from the viewer canvas to screen images of - * different resolutions. A scale factor of 1 means 1 pixel in - * the screen image is displayed as 1 pixel on the canvas, a - * scale factor of 0.5 means 1 pixel in the screen image is - * displayed as 2 pixel on the canvas, etc. - * @see MultiResolutionRenderer - */ - public ViewerOptions screenScales( final double[] s ) - { - values.screenScales = s; - return this; - } - - /** - * Set target rendering time in nanoseconds. - * - * @param t - * Target rendering time in nanoseconds. The rendering time for - * the coarsest rendered scale should be below this threshold. - * @see MultiResolutionRenderer - */ - public ViewerOptions targetRenderNanos( final long t ) - { - values.targetRenderNanos = t; - return this; - } - - /** - * Set how many threads to use for rendering. - * - * @param n - * How many threads to use for rendering. - * @see MultiResolutionRenderer - */ - public ViewerOptions numRenderingThreads( final int n ) - { - values.numRenderingThreads = n; - return this; - } - - /** - * Set how many source groups there are initially. - * - * @param n - * How many source groups to create initially. - */ - public ViewerOptions numSourceGroups( final int n ) - { - values.numSourceGroups = n; - return this; - } - - /** - * Set whether volatile versions of sources should be used if available. - * - * @param v - * whether volatile versions of sources should be used if - * available. - * @see MultiResolutionRenderer - */ - public ViewerOptions useVolatileIfAvailable( final boolean v ) - { - values.useVolatileIfAvailable = v; - return this; - } - - public ViewerOptions msgOverlay( final MessageOverlayAnimator o ) - { - values.msgOverlay = o; - return this; - } - - public ViewerOptions transformEventHandlerFactory( final TransformEventHandlerFactory f ) - { - values.transformEventHandlerFactory = f; - return this; - } - - /** - * Set the factory for creating {@link AccumulateProjector}. This can be - * used to customize how sources are combined. - * - * @param f - * factory for creating {@link AccumulateProjector}. - * @see MultiResolutionRenderer - */ - public ViewerOptions accumulateProjectorFactory( final AccumulateProjectorFactory< ARGBType > f ) - { - values.accumulateProjectorFactory = f; - return this; - } - - /** - * Set the {@link InputTriggerConfig} from which keyboard and mouse action mapping is loaded. - * - * @param c the {@link InputTriggerConfig} from which keyboard and mouse action mapping is loaded - */ - public ViewerOptions inputTriggerConfig( final InputTriggerConfig c ) - { - values.inputTriggerConfig = c; - return this; - } - - /** - * Set the {@link KeyPressedManager} to share - * {@link KeyListener#keyPressed(java.awt.event.KeyEvent)} events with other - * ui-behaviour windows. - * <p> - * The goal is to make keyboard click/drag behaviours work like mouse - * click/drag: When a behaviour is initiated with a key press, the window - * under the mouse receives focus and the behaviour is handled there. - * </p> - * - * @param manager - * @return - */ - public ViewerOptions shareKeyPressedEvents( final KeyPressedManager manager ) - { - values.keyPressedManager = manager; - return this; - } - - /** - * Read-only {@link ViewerOptions} values. - */ - public static class Values - { - private int width = 800; - - private int height = 600; - - private double[] screenScales = new double[] { 1, 0.75, 0.5, 0.25, 0.125 }; - - private long targetRenderNanos = 30 * 1000000l; - - private int numRenderingThreads = 3; - - private int numSourceGroups = 10; - - private boolean useVolatileIfAvailable = true; - - private MessageOverlayAnimator msgOverlay = new MessageOverlayAnimator( 800 ); - - private TransformEventHandlerFactory transformEventHandlerFactory = TransformEventHandler3D::new; - - private AccumulateProjectorFactory< ARGBType > accumulateProjectorFactory = AccumulateProjectorARGB.factory; - - private InputTriggerConfig inputTriggerConfig = null; - - private KeyPressedManager keyPressedManager = null; - - public ViewerOptions optionsFromValues() - { - return new ViewerOptions(). - width( width ). - height( height ). - screenScales( screenScales ). - targetRenderNanos( targetRenderNanos ). - numRenderingThreads( numRenderingThreads ). - numSourceGroups( numSourceGroups ). - useVolatileIfAvailable( useVolatileIfAvailable ). - msgOverlay( msgOverlay ). - transformEventHandlerFactory( transformEventHandlerFactory ). - accumulateProjectorFactory( accumulateProjectorFactory ). - inputTriggerConfig( inputTriggerConfig ); - } - - public int getWidth() - { - return width; - } - - public int getHeight() - { - return height; - } - - public double[] getScreenScales() - { - return screenScales; - } - - public long getTargetRenderNanos() - { - return targetRenderNanos; - } - - public int getNumRenderingThreads() - { - return numRenderingThreads; - } - - public int getNumSourceGroups() - { - return numSourceGroups; - } - - public boolean isUseVolatileIfAvailable() - { - return useVolatileIfAvailable; - } - - public MessageOverlayAnimator getMsgOverlay() - { - return msgOverlay; - } - - public TransformEventHandlerFactory getTransformEventHandlerFactory() - { - return transformEventHandlerFactory; - } - - public AccumulateProjectorFactory< ARGBType > getAccumulateProjectorFactory() - { - return accumulateProjectorFactory; - } - - public InputTriggerConfig getInputTriggerConfig() - { - return inputTriggerConfig; - } - - public KeyPressedManager getKeyPressedManager() - { - return keyPressedManager; - } - } +public class ViewerOptions { + public static class CompressionOptions { + private boolean enabled = false; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(final boolean enable) { + this.enabled = enable; + } + } + + public final Values values = new Values(); + + /** + * Create default {@link ViewerOptions}. + * + * @return default {@link ViewerOptions}. + */ + public static ViewerOptions options() { + return new ViewerOptions(); + } + + /** + * Set width of {@link ViewerPanel} canvas. + */ + public ViewerOptions width(final int w) { + values.width = w; + return this; + } + + public ViewerOptions compressionOptions(final CompressionOptions compressionOptions) { + values.compressionOptions = compressionOptions; + return this; + } + + /** + * Set height of {@link ViewerPanel} canvas. + */ + public ViewerOptions height(final int h) { + values.height = h; + return this; + } + + /** + * Set the number and scale factors for scaled screen images. + * + * @param s Scale factors from the viewer canvas to screen images of + * different resolutions. A scale factor of 1 means 1 pixel in + * the screen image is displayed as 1 pixel on the canvas, a + * scale factor of 0.5 means 1 pixel in the screen image is + * displayed as 2 pixel on the canvas, etc. + * @see MultiResolutionRenderer + */ + public ViewerOptions screenScales(final double[] s) { + values.screenScales = s; + return this; + } + + /** + * Set target rendering time in nanoseconds. + * + * @param t Target rendering time in nanoseconds. The rendering time for + * the coarsest rendered scale should be below this threshold. + * @see MultiResolutionRenderer + */ + public ViewerOptions targetRenderNanos(final long t) { + values.targetRenderNanos = t; + return this; + } + + /** + * Set how many threads to use for rendering. + * + * @param n How many threads to use for rendering. + * @see MultiResolutionRenderer + */ + public ViewerOptions numRenderingThreads(final int n) { + values.numRenderingThreads = n; + return this; + } + + /** + * Set how many source groups there are initially. + * + * @param n How many source groups to create initially. + */ + public ViewerOptions numSourceGroups(final int n) { + values.numSourceGroups = n; + return this; + } + + /** + * Set whether volatile versions of sources should be used if available. + * + * @param v whether volatile versions of sources should be used if + * available. + * @see MultiResolutionRenderer + */ + public ViewerOptions useVolatileIfAvailable(final boolean v) { + values.useVolatileIfAvailable = v; + return this; + } + + public ViewerOptions msgOverlay(final MessageOverlayAnimator o) { + values.msgOverlay = o; + return this; + } + + public ViewerOptions transformEventHandlerFactory(final TransformEventHandlerFactory f) { + values.transformEventHandlerFactory = f; + return this; + } + + /** + * Set the factory for creating {@link AccumulateProjector}. This can be + * used to customize how sources are combined. + * + * @param f factory for creating {@link AccumulateProjector}. + * @see MultiResolutionRenderer + */ + public ViewerOptions accumulateProjectorFactory(final AccumulateProjectorFactory<ARGBType> f) { + values.accumulateProjectorFactory = f; + return this; + } + + /** + * Set the {@link InputTriggerConfig} from which keyboard and mouse action mapping is loaded. + * + * @param c the {@link InputTriggerConfig} from which keyboard and mouse action mapping is loaded + */ + public ViewerOptions inputTriggerConfig(final InputTriggerConfig c) { + values.inputTriggerConfig = c; + return this; + } + + /** + * Set the {@link KeyPressedManager} to share + * {@link KeyListener#keyPressed(java.awt.event.KeyEvent)} events with other + * ui-behaviour windows. + * <p> + * The goal is to make keyboard click/drag behaviours work like mouse + * click/drag: When a behaviour is initiated with a key press, the window + * under the mouse receives focus and the behaviour is handled there. + * </p> + * + * @param manager + * @return + */ + public ViewerOptions shareKeyPressedEvents(final KeyPressedManager manager) { + values.keyPressedManager = manager; + return this; + } + + /** + * Read-only {@link ViewerOptions} values. + */ + public static class Values { + private int width = 800; + + private int height = 600; + + private double[] screenScales = new double[]{1, 0.75, 0.5, 0.25, 0.125}; + + private long targetRenderNanos = 30 * 1000000l; + + private int numRenderingThreads = 3; + + private int numSourceGroups = 10; + + private boolean useVolatileIfAvailable = true; + + private MessageOverlayAnimator msgOverlay = new MessageOverlayAnimator(800); + + private TransformEventHandlerFactory transformEventHandlerFactory = TransformEventHandler3D::new; + + private AccumulateProjectorFactory<ARGBType> accumulateProjectorFactory = AccumulateProjectorARGB.factory; + + private InputTriggerConfig inputTriggerConfig = null; + + private KeyPressedManager keyPressedManager = null; + + private CompressionOptions compressionOptions = new CompressionOptions(); + + public ViewerOptions optionsFromValues() { + return new ViewerOptions(). + width(width). + height(height). + screenScales(screenScales). + targetRenderNanos(targetRenderNanos). + numRenderingThreads(numRenderingThreads). + numSourceGroups(numSourceGroups). + useVolatileIfAvailable(useVolatileIfAvailable). + msgOverlay(msgOverlay). + transformEventHandlerFactory(transformEventHandlerFactory). + accumulateProjectorFactory(accumulateProjectorFactory). + inputTriggerConfig(inputTriggerConfig). + compressionOptions(compressionOptions); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public double[] getScreenScales() { + return screenScales; + } + + public long getTargetRenderNanos() { + return targetRenderNanos; + } + + public int getNumRenderingThreads() { + return numRenderingThreads; + } + + public int getNumSourceGroups() { + return numSourceGroups; + } + + public boolean isUseVolatileIfAvailable() { + return useVolatileIfAvailable; + } + + public MessageOverlayAnimator getMsgOverlay() { + return msgOverlay; + } + + public TransformEventHandlerFactory getTransformEventHandlerFactory() { + return transformEventHandlerFactory; + } + + public AccumulateProjectorFactory<ARGBType> getAccumulateProjectorFactory() { + return accumulateProjectorFactory; + } + + public InputTriggerConfig getInputTriggerConfig() { + return inputTriggerConfig; + } + + public KeyPressedManager getKeyPressedManager() { + return keyPressedManager; + } + + public CompressionOptions getCompressionOptions() { + return compressionOptions; + } + } }