scala - 在 scala Play 框架中流式传输 ByteArrayOutputStream 的结果
问题描述
我正在尝试将 svg 图像转换为 scala 播放框架中的 jpeg 图像。
我用蜡染,效果很好。
现在我喜欢将输出流式传输到操作结果中,而不是将 ByteArrayOutputStream 转换为将整个输出加载到内存中的 ByteArray。
我怎样才能做到这一点?
这是项目代码,无需流式输出即可工作:
构建.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/路由
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)
}
推荐阅读
- html - CSS Center 在最小宽度下裁剪图像
- android - 如何实现一个安全的系统BroadcastReceiver
- c# - System.Net.Http.HttpClient 4 错误
- r - 如何制作每个 X 轴项目有两个值的垂直条形图
- c++ - c ++析构函数不会删除对象本身,是什么?
- javascript - 用户单击 Chrome 扩展程序中的弹出窗口后,如何保持音频播放?
- twilio - 运行两个 TWIML
- reactjs - 当我检查元素时,源总是打开的
- angular - 如果值为空,是否可以在 Angular Material Multiple Select 中显示值标签?
- google-data-studio - 在 Google Data Studio 中计算选项卡过滤器和整体之间差异的方法?