Skip to content

Commit

Permalink
Image: Replace BufferedImage-based image reading with SCIFIO (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
skalarproduktraum committed May 29, 2024
1 parent 881bd25 commit 8f24cea
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 22 deletions.
91 changes: 69 additions & 22 deletions src/main/kotlin/graphics/scenery/utils/Image.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package graphics.scenery.utils

import graphics.scenery.volumes.Colormap
import io.scif.SCIFIO
import net.imglib2.img.Img
import net.imglib2.type.numeric.NumericType
import net.imglib2.type.numeric.integer.UnsignedByteType
import net.imglib2.type.numeric.real.FloatType
Expand All @@ -12,6 +13,9 @@ import org.lwjgl.util.tinyexr.EXRImage
import org.lwjgl.util.tinyexr.EXRVersion
import org.lwjgl.util.tinyexr.TinyEXR
import org.lwjgl.util.tinyexr.TinyEXR.FreeEXRImage
import org.scijava.Context
import org.scijava.io.handle.DataHandleService
import org.scijava.io.location.BytesLocation
import java.awt.Color
import java.awt.color.ColorSpace
import java.awt.geom.AffineTransform
Expand All @@ -22,7 +26,9 @@ import java.io.InputStream
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.util.*
import javax.imageio.ImageIO
import kotlin.system.measureNanoTime
import kotlin.time.Duration
import kotlin.time.Duration.Companion.nanoseconds

/**
* Utility class for reading RGBA images via [BufferedImage].
Expand All @@ -34,6 +40,7 @@ open class Image(val contents: ByteBuffer, val width: Int, val height: Int, val

companion object {
protected val logger by lazyLogger()
protected val scifio = SCIFIO()

private val StandardAlphaColorModel = ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_sRGB),
Expand Down Expand Up @@ -71,6 +78,8 @@ open class Image(val contents: ByteBuffer, val width: Int, val height: Int, val
val imageData: ByteBuffer
val pixels: IntArray
val buffer: ByteArray
var width: Int
var height: Int

when {
extension.lowercase().endsWith("exr") -> {
Expand Down Expand Up @@ -180,50 +189,88 @@ open class Image(val contents: ByteBuffer, val width: Int, val height: Int, val

else -> {
if(extension.lowercase().endsWith("tga")) {
try {
imageData = try {
val reader = BufferedInputStream(stream)
buffer = ByteArray(stream.available())
reader.read(buffer)
reader.close()

pixels = TGAReader.read(buffer, TGAReader.ARGB)
val width = TGAReader.getWidth(buffer)
val height = TGAReader.getHeight(buffer)
bi = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
bi.setRGB(0, 0, width, height, pixels, 0, width)
pixels = TGAReader.read(buffer, TGAReader.RGBA)
width = TGAReader.getWidth(buffer)
height = TGAReader.getHeight(buffer)
val b = ByteBuffer.allocateDirect(width * height * 4)
b.asIntBuffer().put(pixels)
b
} catch (e: IOException) {
Colormap.logger.error("Could not read image from TGA. ${e.message}")
bi = BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)
bi.setRGB(0, 0, 1, 1, intArrayOf(255, 0, 0), 0, 1)
logger.error("Could not read image from TGA. ${e.message}")
width = 1
height = 1
ByteBuffer.wrap(byteArrayOf(127,127,127,0))
}

} else {
try {
val reader = BufferedInputStream(stream)
bi = ImageIO.read(stream)
imageData = try {
// TODO: Improve this code here
val ctx = Context()//PluginService::class.java, SCIFIOService::class.java, DataHandleService::class.java)
val ds = ctx.getService(DataHandleService::class.java)
val h = ds.create(BytesLocation(stream.readAllBytes()))
val opener = scifio.io().getOpener(h.get())
logger.info("Opener: $opener")
val img = opener.open(h.get()) as? Img<UnsignedByteType>
logger.info("opened $img!")
val reader = scifio.initializer().initializeReader(h.get())
logger.info("Got reader")
val plane = reader.openPlane(0, 0)
logger.info("Opened plane with ${plane.bytes.size}b!")
val b = ByteBuffer.allocateDirect(plane.bytes.size)
b.put(plane.bytes)
b.flip()
width = plane.lengths[0].toInt()
height = plane.lengths[1].toInt()
reader.close()
b
} catch (e: IOException) {
Colormap.logger.error("Could not read image: ${e.message}")
bi = BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)
bi.setRGB(0, 0, 1, 1, intArrayOf(255, 0, 0), 0, 1)
logger.error("Could not read image: ${e.message}")
width = 1
height = 1
ByteBuffer.wrap(byteArrayOf(127,127,127,0))
}
}

stream.close()

if(flip) {
// convert to OpenGL UV space
flippedImage = createFlipped(bi)
imageData = bufferedImageToRGBABuffer(flippedImage)
} else {
imageData = bufferedImageToRGBABuffer(bi)
flipInPlace(imageData, width, height)
}

return Image(imageData, bi.width, bi.height)
return Image(imageData, width, height)
}
}
}

private fun flipInPlace(imageData: ByteBuffer, width: Int, height: Int) {
val view = imageData.duplicate().order(ByteOrder.LITTLE_ENDIAN)
(0..height / 2).forEach { index ->

Check warning on line 254 in src/main/kotlin/graphics/scenery/utils/Image.kt

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/main/kotlin/graphics/scenery/utils/Image.kt#L254

Using the forEach method on ranges has a heavy performance cost. Prefer using simple for loops.
val sourceIndex = index * width * 4
val destIndex = width * height * 4 - (index + 1) * width * 4

val source = ByteArray(width * 4)
view.position(sourceIndex)
view.get(source)

val dest = ByteArray(width * 4)
view.position(destIndex)
view.get(dest)

view.position(sourceIndex)
view.put(dest)

view.position(destIndex)
view.put(source)
}
}

/**
* Creates an Image from a resource given in [path], with [baseClass] as basis for the search path.
* [path] is expected to end in an extension (e.g., ".png"), such that the file type can be determined.
Expand Down
1 change: 1 addition & 0 deletions src/main/kotlin/graphics/scenery/utils/TGAReader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import java.io.IOException

object TGAReader {
val ARGB = Order(16, 8, 0, 24)
val RGBA = Order(24, 16, 8, 0)
val ABGR = Order(0, 8, 16, 24)
fun getWidth(buffer: ByteArray): Int {
return buffer[12].toInt() and 0xFF or (buffer[13].toInt() and 0xFF shl 8)
Expand Down

0 comments on commit 8f24cea

Please sign in to comment.