Reputation: 149
I am using Scala Play Framework to send images to the client in a multipart form data as a response to a get request.
I have the images stored in the BufferedImage
format. Currently, I send the images back to the client using this getResult
method:
@Singleton
class ResultController @Inject()(val controllerComponents: ControllerComponents) extends BaseController with DefaultWriteables{
class ResultForm(seq: Seq[BufferedImage]){
val (leftRotation, rightRotation, backRotation) = seq.zip(
Seq("left", "right", "back")
).map{ case (bufferedImage: BufferedImage, partName: String) =>
val bos = new ByteArrayOutputStream()
ImageIO.write(bufferedImage, "png", bos)
MultipartFormData.FilePart(
partName,
s"${partName}_result.png",
Some("image/png"),
ByteString.fromArray(bos.toByteArray())
)
} match {
case Seq(l, r, b) => (l, r, b)
}
def getResponse() = {
MultipartFormData(
dataParts = Map[String, Seq[String]](),
files = Seq(leftRotation, rightRotation, backRotation),
badParts =Seq()
)
}
}
implicit def writeableOf_MultipartFormDataWithBs(
codec: Codec,
contentType: Option[String]
):play.api.http.Writeable[MultipartFormData[akka.util.ByteString]] = {
writeableOf_MultipartFormData(
codec,
Writeable[MultipartFormData.FilePart[akka.util.ByteString]](
(bs: MultipartFormData.FilePart[akka.util.ByteString]) => bs.ref,
contentType
)
)
}
def getResult(accessKey: String) = Action{request =>
val jobResult = GeneratorData.getJobResult(accessKey)
jobResult match {
case Some(files) => {
val rf = new ResultForm(files)
Ok(
rf.getResponse()
)(
writeableOf_MultipartFormDataWithBs(
Codec.iso_8859_1,
contentType = Some("multipart/form-data")
)
)
}
case None => BadRequest(Json.toJson(
new ErrorResponse("The result was not found on the server")
))
}
}
}
However, in client-side javascript, Response.formData() only works in chrome and opera, but firefox throws a TypeError: Could not parse content as FormData.
exception. This is possibly due to some wild conversions of the image formats that are going on, and the definition of a custom writer.
The whole thing would be way easier, if instead of an akka ByteString I just passed a TemporaryFile
for which the writer is well-defined by the framework, but I can't seem to find a way to create a TemporaryFile, documentation doesn't list any methods like "create".
There is a TemporaryFileCreator trait, but none of it's subclasses seem to have methods that convert from any type of in-memory file to a TemporaryFile. They do, however, have methods to specify a path to the file, but I need to serve the files using RAM only.
So, is there a way to create a TemporaryFile from an in-memory file data? Or maybe a way to send three images as multipart so that firefox, not just opera and chromium can parse the result? Base64 is also a solution, but I would prefer to do this the "right" way.
Upvotes: 0
Views: 242
Reputation: 149
So I have implemented a simple example in python and it turns out this is a Firefox bug. You can trace the bug report here: https://bugzilla.mozilla.org/show_bug.cgi?id=1752761
Upvotes: 0