Skip to content

Commit

Permalink
Add fall-back serializers for RawSourceState
Browse files Browse the repository at this point in the history
  • Loading branch information
hanslovsky committed Nov 26, 2019
1 parent ba6d928 commit a6f5aa8
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import net.imglib2.exception.IncompatibleTypeException;
import org.janelia.saalfeldlab.paintera.serialization.sourcestate.SourceStateSerialization;
import org.janelia.saalfeldlab.paintera.state.LabelSourceState;
import org.janelia.saalfeldlab.paintera.state.RawSourceState;
import org.janelia.saalfeldlab.paintera.state.SourceInfo;
import org.janelia.saalfeldlab.paintera.state.SourceState;
import org.scijava.plugin.Plugin;
Expand Down Expand Up @@ -172,9 +173,11 @@ public static void populate(
if (LabelSourceState.class.equals(clazz)) {
LOG.info("Trying to de-serialize deprecated LabelSourceState into ConnectomicsLabelState");
sourceStates[k] = gson.fromJson(state.get(STATE_KEY), (Type) clazz);
} else {
} else if (RawSourceState.class.equals(clazz)) {
LOG.info("Trying to de-serialize deprecated RawSourceState into ConnectomicsRawState");
sourceStates[k] = gson.fromJson(state.get(STATE_KEY), (Type) clazz);
} else
sourceStates[k] = gson.fromJson(state.get(STATE_KEY), clazz);
}
logSourceForDependencies.accept(k, sourceStates[k]);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.janelia.saalfeldlab.paintera.serialization.sourcestate;

import java.lang.invoke.MethodHandles;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import net.imglib2.converter.ARGBColorConverter;
Expand All @@ -11,11 +9,11 @@
import org.janelia.saalfeldlab.paintera.serialization.PainteraSerialization;
import org.janelia.saalfeldlab.paintera.state.RawSourceState;
import org.janelia.saalfeldlab.paintera.state.SourceState;
import org.scijava.plugin.Plugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Plugin(type= PainteraSerialization.PainteraDeserializer.class)
import java.lang.invoke.MethodHandles;

public class RawSourceStateDeserializer extends
SourceStateSerialization
.SourceStateDeserializerWithoutDependencies<RawSourceState<?, ?>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import java.util.function.Supplier
// NB: If this ever becomes dataset dependent, we should create individual classes for
// - dataset
// - multi-scale group
// - paitnera dataset
// - paintera dataset

class N5BackendChannel<D, T> constructor(
override val container: N5Writer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import org.janelia.saalfeldlab.paintera.serialization.GsonExtensions
import org.janelia.saalfeldlab.paintera.serialization.PainteraSerialization
import org.janelia.saalfeldlab.paintera.serialization.SerializationHelpers
import org.janelia.saalfeldlab.paintera.state.*
import org.janelia.saalfeldlab.util.Colors
import org.scijava.plugin.Plugin
import org.slf4j.LoggerFactory
import java.lang.invoke.MethodHandles
Expand Down Expand Up @@ -143,6 +144,8 @@ class ConnectomicsRawState<D, T>(override val backend: ConnectomicsRawBackend<D,
const val CONVERTER = "converter"
const val CONVERTER_MIN = "min"
const val CONVERTER_MAX = "max"
const val CONVERTER_ALPHA = "alpha"
const val CONVERTER_COLOR = "color"
const val INTERPOLATION = "interpolation"
const val IS_VISIBLE = "isVisible"
}
Expand All @@ -158,6 +161,8 @@ class ConnectomicsRawState<D, T>(override val backend: ConnectomicsRawBackend<D,
JsonObject().let { m ->
m.addProperty(CONVERTER_MIN, state.converter.min)
m.addProperty(CONVERTER_MAX, state.converter.max)
m.addProperty(CONVERTER_ALPHA, state.converter.alphaProperty().get())
m.addProperty(CONVERTER_COLOR, Colors.toHTML(state.converter.color))
map.add(CONVERTER, m)
}
map.add(INTERPOLATION, context.serialize(state.interpolation))
Expand All @@ -183,6 +188,8 @@ class ConnectomicsRawState<D, T>(override val backend: ConnectomicsRawBackend<D,
json.getJsonObject(CONVERTER)?.let { converter ->
converter.getDoubleProperty(CONVERTER_MIN)?.let { state.converter.min = it }
converter.getDoubleProperty(CONVERTER_MAX)?.let { state.converter.max = it }
converter.getDoubleProperty(CONVERTER_ALPHA)?.let { state.converter.alphaProperty().value = it }
converter.getStringProperty(CONVERTER_COLOR)?.let { state.converter.color = Colors.toARGBType(it) }
}
}
.also { state -> json.getProperty(INTERPOLATION)?.let { state.interpolation = context.deserialize(it, Interpolation::class.java) } }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package org.janelia.saalfeldlab.paintera.state.raw

import bdv.viewer.Interpolation
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import net.imglib2.realtransform.AffineTransform3D
import net.imglib2.type.NativeType
import net.imglib2.type.numeric.ARGBType
import net.imglib2.type.numeric.RealType
import net.imglib2.type.volatiles.AbstractVolatileRealType
import org.janelia.saalfeldlab.paintera.composition.Composite
import org.janelia.saalfeldlab.paintera.data.n5.N5DataSource
import org.janelia.saalfeldlab.paintera.data.n5.N5Meta
import org.janelia.saalfeldlab.paintera.serialization.GsonExtensions
import org.janelia.saalfeldlab.paintera.serialization.SerializationHelpers
import org.janelia.saalfeldlab.paintera.serialization.StatefulSerializer
import org.janelia.saalfeldlab.paintera.serialization.sourcestate.LabelSourceStateDeserializer
import org.janelia.saalfeldlab.paintera.serialization.sourcestate.SourceStateSerialization
import org.janelia.saalfeldlab.paintera.state.RawSourceState
import org.janelia.saalfeldlab.paintera.state.SourceState
import org.janelia.saalfeldlab.paintera.state.raw.n5.N5BackendRaw
import org.janelia.saalfeldlab.util.Colors
import org.scijava.plugin.Plugin
import org.slf4j.LoggerFactory
import java.lang.invoke.MethodHandles
import java.lang.reflect.Type
import java.util.function.IntFunction
import java.util.function.Supplier

class RawSourceStateFallbackDeserializer<D, T>(private val arguments: StatefulSerializer.Arguments) : JsonDeserializer<SourceState<*, *>>
where D: RealType<D>,
D: NativeType<D>,
T: AbstractVolatileRealType<D, T>,
T: NativeType<T> {

private val fallbackDeserializer: LabelSourceStateDeserializer<*> = LabelSourceStateDeserializer.create(arguments)

override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): SourceState<*, *> {
return json.getN5MetaAndTransform(context)?.let { (meta, transform) ->
val (resolution, offset) = transform.toOffsetAndResolution()
val backend = N5BackendRaw<D, T>(
meta.writer,
meta.dataset,
resolution,
offset,
arguments.viewer.queue,
0,
with (GsonExtensions) { json.getStringProperty("name") } ?: "<N/A>")
ConnectomicsRawState(backend)
.also { LOG.debug("Successfully converted state {} into {}", json, it) }
.also { s -> SerializationHelpers.deserializeFromClassInfo<Composite<ARGBType, ARGBType>>(json.asJsonObject, context, "compositeType", "composite")?.let { s.composite = it } }
// TODO what about other converter properties like user-defined colors?
.also { s -> with (GsonExtensions) { s.updateConverterSettings(json.getJsonObject("converter")) } }
.also { s -> with (GsonExtensions) { json.getProperty("interpolation")?.let { context.deserialize<Interpolation>(it, Interpolation::class.java) }?.let { s.interpolation = it } } }
.also { s -> with (GsonExtensions) { json.getBooleanProperty("isVisible") }?.let { s.isVisible = it } }
} ?: run {
// TODO should this throw an exception instead? could be handled downstream with fall-back and a warning dialog
LOG.warn(
"Unable to de-serialize/convert deprecated `{}' into `{}', falling back using `{}'. Support for `{}' has been deprecated and may be removed in the future.",
RawSourceState::class.java.simpleName,
ConnectomicsRawState::class.java.simpleName,
LabelSourceStateDeserializer::class.java.simpleName,
RawSourceState::class.java.simpleName)
fallbackDeserializer.deserialize(json, typeOfT, context)
}
}

companion object {

private val LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass())

private fun JsonElement.getN5MetaAndTransform(
context: JsonDeserializationContext,
typeKey: String = SourceStateSerialization.SOURCE_TYPE_KEY,
dataKey: String = SourceStateSerialization.SOURCE_KEY,
metaTypeKey: String = "metaType",
metaKey: String = "meta",
transformKey: String = "transform"): Pair<N5Meta, AffineTransform3D>? = with(GsonExtensions) {
val type = getStringProperty(typeKey)
val data = getJsonObject(dataKey)
if (N5DataSource::class.java.name == type)
Pair(
context.deserialize(data?.get(metaKey), Class.forName(data?.getStringProperty(metaTypeKey))) as N5Meta,
context.deserialize(data?.get(transformKey), AffineTransform3D::class.java))
else
null
}

private fun AffineTransform3D.toOffsetAndResolution() = Pair(
DoubleArray(3) { this[it, it] },
DoubleArray(3) { this[it, 3] })

private fun ConnectomicsRawState<*, *>.updateConverterSettings(json: JsonObject?) = json?.let { j ->
val c = converter()
with (GsonExtensions) {
j.getDoubleProperty("alpha")?.let { c.alphaProperty().value = it }
j.getDoubleProperty("min")?.let { c.setMin(it) }
j.getDoubleProperty("max")?.let { c.setMax(it) }
j.getStringProperty("color")?.let { c.setColor(Colors.toARGBType(it)) }
}
}
}


@Plugin(type = StatefulSerializer.DeserializerFactory::class)
class Factory<D, T>: StatefulSerializer.DeserializerFactory<SourceState<*, *>, RawSourceStateFallbackDeserializer<D, T>>
where D: RealType<D>,
D: NativeType<D>,
T: AbstractVolatileRealType<D, T>,
T: NativeType<T>{
override fun createDeserializer(
arguments: StatefulSerializer.Arguments,
projectDirectory: Supplier<String>,
dependencyFromIndex: IntFunction<SourceState<*, *>>
): RawSourceStateFallbackDeserializer<D, T> =
RawSourceStateFallbackDeserializer(arguments)

override fun getTargetClass(): Class<SourceState<*, *>> = RawSourceState::class.java as Class<SourceState<*, *>>

}
}

Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import java.util.function.Supplier
// NB: If this ever becomes dataset dependent, we should create individual classes for
// - dataset
// - multi-scale group
// - paitnera dataset
// - paintera dataset

class N5BackendRaw<D, T> constructor(
override val container: N5Writer,
Expand Down

0 comments on commit a6f5aa8

Please sign in to comment.