1
votes

I'm trying to store user-uploaded images in my application which is written by scala and play framework 2.2.x I've deployed my app in heroku. Heroku does not allow me to save my file in file system. So I've tried to store my file in data base.

here is the code that I use for storing image :

def updateImage(id: Long, image: Array[Byte]) = {
val selected = getById(id)

DB.withConnection {
  implicit c =>
    SQL("update subcategory set image={image} where id = {id}").on('id -> id, 'image -> image).executeUpdate()
}
selected }

and here is the code that I use to retreive my image :

  def getImageById(id: Long): Array[Byte] = DB.withConnection {
  implicit c =>
  val all = SQL("select image from subcategory where id = {id}").on('id -> id)().map {

    case Row(image: Array[Byte]) => image
    case Row(Some(image: Array[Byte])) => image

    case Row(image: java.sql.Blob )=> image.getBytes(0 , image.length().toInt)
  }
  all.head
 }

The problem is: when I use H2 database and blob column, I get the "Match Error" exception. When I use Postgresql and bytea column, I got no error but when I retrieve the image, It's in hex format and some of the bytes in the beginning of the array are missing.

1
Store blob images in database is really a very bad idea. I feel dirty when I see something like this. try to save your image in a cloud storage like Amazon S3, or imageshack it's better, unless you will not show this image in a web page. Also try to do all operations relative to the image processing in the client side, like resize, crop beacause there is no good working solution with Heroku. - Ben Rhouma Zied
Thanx Ben, but I'm new to play framework (and scala) and couldn't find a good tutorial on how to use Amazon S3 on play. - fahim ayat

1 Answers

0
votes

According to the PostgreSQL documentation, bytea stores the length of the array in the four bytes at the beginning of the array. These are stripped when you read the row, so that's why they seem to be "missing" when you compare the data in Scala with the data in the DB.

You will have to set the response's content-type to the appropriate value if you want the web browser to display the image correctly, as otherwise it does not know it is receiving image data. The Ok.sendFile helper does it for you. Otherwise you will have to do it by hand:

  def getPicture = Action {
      SimpleResult(
          header = ResponseHeader(200),
          body = Enumerator(pictureByteArray))
      .as(pictureContentType)
  }

In the example above, pictureByteArray is the Array[Byte] containing the picture data from your database, and pictureContentType is a string with the appropriate content type (for example, image/jpeg).

This is all quite well explained in the Play documentation.