我正在尝试在scala播放框架中将svg图像转换为jpeg图像。
我使用了蜡染,它工作正常。
现在,我喜欢在操作结果中流式传输输出,而不是将ByteArrayOutputStream转换为ByteArray将整个输出加载到内存中。
我该怎么做?
这里是项目代码,无需流输出即可工作:
build.sbt
name := "svg2png"
version := "1.0-SNAPSHOT"
lazy val root = (project in file(".")).enablePlugins(PlayScala)
resolvers += Resolver.sonatypeRepo("snapshots")
scalaVersion := "2.12.3"
libraryDependencies ++= Seq(
jdbc,
guice,
"org.apache.xmlgraphics" % "batik-transcoder" % "1.11",
"org.apache.xmlgraphics" % "batik-codec" % "1.11"
)
/ project / plugins.sbt
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.6")
/ project / build.properties
sbt.version=1.0.2
/ conf / routes
GET / controllers.Application.index
GET /image controllers.Application.getImage
/ conf / application.conf
play.filters.enabled += "play.filters.cors.CORSFilter"
play.filters {
hosts {
allowed = ["."]
}
headers {
contentSecurityPolicy = null
}
}
play.i18n {
langs = [ "en" ]
}
contexts {
imageService {
fork-join-executor {
parallelism-factor = 4.0
parallelism-max = 8
}
}
}
/ app / controllers / Application.scala
package controllers
import play.api.mvc._
import javax.inject._
import scala.concurrent.ExecutionContext
@Singleton
class Application @Inject()(imageService: services.ImageService,
cc: ControllerComponents)(implicit exec: ExecutionContext) extends AbstractController(cc) {
def index = Action {
Ok("test app").as(HTML)
}
def getImage : Action[AnyContent] = Action.async {
imageService.getImage.map{res => Ok(res).as("image/jpeg") }
}
}
/ app / services / ImageService.scala
package services
import java.io.{ByteArrayOutputStream, StringReader}
import com.google.inject.{Inject, Singleton}
import scala.concurrent.{ExecutionContext, Future}
import akka.actor.ActorSystem
import org.apache.batik.transcoder.image.JPEGTranscoder
import org.apache.batik.transcoder.TranscoderInput
import org.apache.batik.transcoder.TranscoderOutput
@Singleton
class ImageService @Inject()(actorSystem: ActorSystem) {
implicit val AnalyticsServiceExecutionContext: ExecutionContext = actorSystem.dispatchers.lookup("contexts.imageService")
def getImage: Future[Array[Byte]] = {
Future {
val t: JPEGTranscoder = new JPEGTranscoder
t.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, new java.lang.Float(0.8))
val imageSVGString: String =
"""<svg width="1000" height="1000" viewBox="0 0 1000 1000" version="1.1"
| xmlns="http://www.w3.org/2000/svg"
| xmlns:xlink="http://www.w3.org/1999/xlink">
| <circle cx="500" cy="500" r="300" fill="lightblue" />
|</svg>
""".stripMargin
val input: TranscoderInput = new TranscoderInput(new StringReader(imageSVGString))
val outputStream = new ByteArrayOutputStream
val output: TranscoderOutput = new TranscoderOutput(outputStream)
t.transcode(input, output)
outputStream.toByteArray
}
}
}
这对我有用:
svg match {
case None => NotFound
case Some(svg) =>
val svgImage = new TranscoderInput(new StringReader(svg))
val pngOstream = new ByteArrayOutputStream
val outputPngImage = new TranscoderOutput(pngOstream)
val converter = fileExtension match {
case "png" => new PNGTranscoder()
case _ => new JPEGTranscoder()
}
if(converter.isInstanceOf[JPEGTranscoder]){
converter.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, (0.8).toFloat)
}
converter.transcode(svgImage, outputPngImage)
Ok(pngOstream.toByteArray).as("image/" + fileExtension)
}