Skip to content

Commit

Permalink
A single DiskResolver is now capable of creating output of different …
Browse files Browse the repository at this point in the history
…types (e.g., thumbnail and audio clip).
  • Loading branch information
Ralph Gasser committed Nov 7, 2024
1 parent 8b1b659 commit 2d8480a
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ interface Resolver {
* Attempts to resolve the provided [RetrievableId] to a [Resolvable] using this [Resolver].
*
* @param id The [RetrievableId] to resolve.
* @param suffix The suffix of the filename.
* @return [Resolvable] or null, if [RetrievableId] could not be resolved.
*/
fun resolve(id: RetrievableId) : Resolvable?
fun resolve(id: RetrievableId, suffix: String) : Resolvable?

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,13 @@ class DiskResolver : ResolverFactory {
*/
override fun newResolver(schema: Schema, parameters: Map<String, String>): Resolver {
val location = Paths.get(parameters["location"] ?: "./thumbnails/${schema.name}")
val mimeType = MimeType.valueOf(parameters["mimeType"] ?: "JPG")
return Instance(location, mimeType)
return Instance(location)
}

/**
* The [Resolver] generated by this [DiskResolver].
*/
private class Instance(private val location: Path, private val mimeType: MimeType) : Resolver {
private class Instance(private val location: Path) : Resolver {
init {
/* Make sure, directory exists. */
if (!Files.exists(this.location)) {
Expand All @@ -47,20 +46,19 @@ class DiskResolver : ResolverFactory {
* Resolves the provided [RetrievableId] to a [Resolvable] using this [Resolver].
*
* @param id The [RetrievableId] to resolve.
* @param suffix The suffix of the filename.
* @return [Resolvable] or null, if [RetrievableId] could not be resolved.
*/
override fun resolve(id: RetrievableId): Resolvable = DiskResolvable(id)

override fun resolve(id: RetrievableId, suffix: String): Resolvable = DiskResolvable(id, suffix)

/**
* A [Resolvable] generated by this [DiskResolver].
*/
inner class DiskResolvable(override val retrievableId: RetrievableId) : Resolvable {
val path: Path
get() = this@Instance.location.resolve("$retrievableId.${this@Instance.mimeType.fileExtension}")
override val mimeType: MimeType
get() = this@Instance.mimeType

inner class DiskResolvable(override val retrievableId: RetrievableId, suffix: String) : Resolvable {
val path: Path = this@Instance.location.resolve("${retrievableId}.$suffix")
override val mimeType: MimeType by lazy {
MimeType.getMimeType(this.path) ?: MimeType.UNKNOWN
}
override fun exists(): Boolean = Files.exists(this.path)
override fun openInputStream(): InputStream = Files.newInputStream(this.path, StandardOpenOption.READ)
override fun openOutputStream(): OutputStream = Files.newOutputStream(this.path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,8 @@ enum class MimeType(val fileExtension: String, val mimeType: String, val mediaTy
OFF("off", "application/3d-off", MediaType.MESH),
GLTF("gltf", "model/gltf+json", MediaType.MESH),




//Unknown type
UNKNOWN("", "", MediaType.NONE)
;
UNKNOWN("", "", MediaType.NONE);

companion object {
fun getMimeType(fileName: String): MimeType? = try {
Expand All @@ -80,6 +76,6 @@ enum class MimeType(val fileExtension: String, val mimeType: String, val mediaTy
null
}

val allValid = MimeType.values().filter { it != UNKNOWN }.toSet()
val allValid = entries.filter { it != UNKNOWN }.toSet()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class ThumbnailExporter : ExporterFactory {
override fun toFlow(scope: CoroutineScope): Flow<Retrievable> = this.input.toFlow(scope).onEach { retrievable ->
try {

val resolvable = this.context.resolver.resolve(retrievable.id)
val resolvable = this.context.resolver.resolve(retrievable.id, ".${this.mimeType.fileExtension}")

val contentIds = this.contentSources?.let {
retrievable.filteredAttribute(ContentAuthorAttribute::class.java)?.getContentIds(it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import kotlinx.coroutines.flow.onEach
import org.bytedeco.javacpp.PointerScope
import org.bytedeco.javacv.FFmpegFrameGrabber
import org.bytedeco.javacv.Java2DFrameConverter
import org.bytedeco.javacv.Java2DFrameUtils
import org.vitrivr.engine.core.context.IndexContext
import org.vitrivr.engine.core.model.retrievable.Retrievable
import org.vitrivr.engine.core.model.retrievable.attributes.SourceAttribute
Expand Down Expand Up @@ -78,7 +77,7 @@ class VideoPreviewExporter : ExporterFactory {
override fun toFlow(scope: CoroutineScope): Flow<Retrievable> = this.input.toFlow(scope).onEach { retrievable ->
val source = retrievable.filteredAttribute(SourceAttribute::class.java)?.source ?: return@onEach
if (source.type == MediaType.VIDEO) {
val resolvable = this.context.resolver.resolve(retrievable.id)
val resolvable = this.context.resolver.resolve(retrievable.id, ".${this.mimeType.fileExtension}")
if (resolvable != null) {
val writer = when (mimeType) {
MimeType.JPEG,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ import org.vitrivr.engine.core.model.mesh.texturemodel.Model3d
import org.vitrivr.engine.core.model.mesh.texturemodel.util.entropyoptimizer.EntopyCalculationMethod
import org.vitrivr.engine.core.model.mesh.texturemodel.util.entropyoptimizer.EntropyOptimizerStrategy
import org.vitrivr.engine.core.model.mesh.texturemodel.util.entropyoptimizer.OptimizerOptions
import org.vitrivr.engine.core.model.mesh.texturemodel.util.types.Vec3f
import org.vitrivr.engine.core.model.retrievable.Retrievable
import org.vitrivr.engine.core.model.retrievable.attributes.SourceAttribute
import org.vitrivr.engine.core.model.mesh.texturemodel.util.types.Vec3f
import org.vitrivr.engine.core.operators.Operator
import org.vitrivr.engine.core.operators.general.Exporter
import org.vitrivr.engine.core.operators.general.ExporterFactory
import org.vitrivr.engine.core.source.MediaType
import org.vitrivr.engine.core.source.file.MimeType
import org.vitrivr.engine.model3d.lwjglrender.render.RenderOptions
import org.vitrivr.engine.model3d.lwjglrender.window.WindowOptions
import org.vitrivr.engine.model3d.lwjglrender.util.texturemodel.entroopyoptimizer.ModelEntropyOptimizer
import org.vitrivr.engine.model3d.lwjglrender.window.WindowOptions
import org.vitrivr.engine.model3d.renderer.ExternalRenderer
import java.awt.image.BufferedImage
import java.io.ByteArrayOutputStream
Expand All @@ -45,10 +45,10 @@ private val logger: KLogger = KotlinLogging.logger {}
*/
class ModelPreviewExporter : ExporterFactory {
companion object {
val SUPPORTED = setOf(MimeType.GLTF)
val SUPPORTED_INPUT = setOf(MimeType.GLTF)

/** Set of supported output formats. */
val OUTPUT_FORMAT = setOf("gif", "jpg")
val SUPPORTED_OUTPUT = setOf(MimeType.GIF, MimeType.JPG, MimeType.JPEG)

/**
* Renders a preview of the given model as a JPEG image.
Expand Down Expand Up @@ -186,7 +186,7 @@ class ModelPreviewExporter : ExporterFactory {
}
} ?: MimeType.GLTF
val distance = context[name, "distance"]?.toFloatOrNull() ?: 1f
val format = context[name, "format"] ?: "gif"
val format = MimeType.valueOf(context[name, "format"]?.uppercase() ?: "GIF")
val views = context[name, "views"]?.toIntOrNull() ?: 30

logger.debug {
Expand All @@ -202,12 +202,12 @@ class ModelPreviewExporter : ExporterFactory {
private val maxResolution: Int,
mimeType: MimeType,
private val distance: Float,
private val format: String,
private val format: MimeType,
private val views: Int
) : Exporter {
init {
require(mimeType in SUPPORTED) { "ModelPreviewExporter only supports models of format GLTF." }
require(format in OUTPUT_FORMAT) { "ModelPreviewExporter only supports exporting a gif of jpg." }
require(mimeType in SUPPORTED_INPUT) { "ModelPreviewExporter only supports models of format GLTF." }
require(this.format in SUPPORTED_OUTPUT) { "ModelPreviewExporter only supports exporting a gif of jpg." }
}

override fun toFlow(scope: CoroutineScope): Flow<Retrievable> {
Expand All @@ -216,7 +216,7 @@ class ModelPreviewExporter : ExporterFactory {
val source =
retrievable.filteredAttribute(SourceAttribute::class.java)?.source ?: return@onEach
if (source.type == MediaType.MESH) {
val resolvable = this.context.resolver.resolve(retrievable.id)
val resolvable = this.context.resolver.resolve(retrievable.id, ".${this.format.fileExtension}")

val model = retrievable.content[0].content as Model3d
if (resolvable != null) {
Expand All @@ -225,15 +225,20 @@ class ModelPreviewExporter : ExporterFactory {
}

source.newInputStream().use { input ->
if (format == "jpg") {
val preview: BufferedImage = renderPreviewJPEG(model, renderer, this.distance)
resolvable.openOutputStream().use { output ->
ImageIO.write(preview, "jpg", output)
when (format) {
MimeType.JPG,
MimeType.JPEG -> {
val preview: BufferedImage = renderPreviewJPEG(model, renderer, this.distance)
resolvable.openOutputStream().use { output ->
ImageIO.write(preview, "jpg", output)
}
}
MimeType.GIF -> {
val frames = createFramesForGif(model, renderer, this.views, this.distance)
val gif = createGif(frames, 50)
resolvable.openOutputStream().use { output -> output.write(gif!!.toByteArray()) }
}
} else { // format == "gif"
val frames = createFramesForGif(model, renderer, this.views, this.distance)
val gif = createGif(frames, 50)
resolvable.openOutputStream().use { output -> output.write(gif!!.toByteArray()) }
else -> throw IllegalArgumentException("Unsupported mime type $format")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fun fetchExportData(ctx: Context, schema: Schema) {
}

/* Try to resolve resolvable for retrievable ID. */
val resolvable = schema.getExporter(exporterName)?.resolver?.resolve(retrievableId)
val resolvable = schema.getExporter(exporterName)?.resolver?.resolve(retrievableId, ".jpg")
if (resolvable == null) {
ctx.status(404)
ctx.json(ErrorStatus("Failed to resolve data."))
Expand Down

0 comments on commit 2d8480a

Please sign in to comment.