简体   繁体   English

在 Scala Play 框架中流式传输 ByteArrayOutputStream 结果

[英]Streaming ByteArrayOutputStream in Action Result in scala Play Framework

I am trying to convert an svg image to a jpeg image in scala play framework.我正在尝试在 Scala 播放框架中将 svg 图像转换为 jpeg 图像。

I used batik and it worked ok.我使用了蜡染,效果很好。

Now I like to stream the output in the action result, instead of converting ByteArrayOutputStream to a ByteArray which loads the entire output in memory.现在我喜欢在操作结果中流式传输输出,而不是将 ByteArrayOutputStream 转换为将整个输出加载到内存中的 ByteArray。

How can I do that?我怎样才能做到这一点?

Here is the project code, which works without streaming the output:这是项目代码,无需流式传输输出即可工作:

build.sbt生成.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 /project/plugins.sbt

addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.6")

/project/build.properties /project/build.properties

sbt.version=1.0.2

/conf/routes /conf/路由

GET     /                                          controllers.Application.index
GET     /image                                     controllers.Application.getImage

/conf/application.conf /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 /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 /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
    }
  }
}

This works for me:这对我有用:

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)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM