Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lift image upload, resize, store in database, display

Is there a succinct example of how to upload an image, resize it, store it in a database and then serve the image up using Lift?

I'm sure I could piece it together from the file upload, Java 2D API, Lift Mapper and Response APIs. But is there any example code I can follow to do it the 'correct' or recommended way?

like image 539
Joe Avatar asked Sep 10 '09 11:09

Joe


People also ask

Can I upload images directly to the database without storing?

The image can be uploaded directly to the database without storing on the server. But it will increase the database size and web page load time. So, it’s always a good idea to upload images to the server and store file names in the database.

How to store an image in the database?

When storing an image in the database also store userid. You need to create separate userid column in the database table. If any user checks a user portfolio then fetch the images from the database table on the basis of userid and display it.

How to upload image into database and display it using PHP?

How to Upload Image into Database and Display it using PHP ? First, open the C drive, then open the folder WAMP or XAMPP server. Then open the bin folder. Open the PHP version folder (PHP 5.6.31 folder) (KINDLY NOTE THAT IF YOU HAVE ANOTHER VERSION OF PHP YOU SHOULD OPEN THAT ALSO) Then search ...

How to upload image to server and display images?

There are various ways available to upload image to server and display images on the webpage. Generally, in a dynamic web application, the uploaded image is stored in a directory of the server and the file name is inserted in the database.


2 Answers

I did this for a Mapper field linked to s3 by creating a new MappedField. I also have a some code to resize, but haven't tested or deployed (so use with caution).

class MappedS3Image[T<:Mapper[T]](owner: T, val path:String, maxWidth: String, maxHeight:String) extends MappedString[T](owner, 36) {

  def url:String = MappedS3Image.fullImgPath(path, is)

  def setFromUpload(fileHolder: Box[FileParamHolder]) = {
      S3Sender.uploadImageToS3(path, fileHolder).map(this.set(_))
  }

  override def asHtml:Node = <img src={url} style={"max-width:" + maxWidth + ";max-height:"+maxHeight} />
  override def _toForm: Box[Elem] = Full(SHtml.fileUpload(fu=>setFromUpload(Full(fu))))

}


import java.awt.Image 
import java.awt.image.BufferedImage
import javax.imageio.ImageIO
import java.awt.Graphics2D
import java.awt.AlphaComposite

object ImageResizer {

    def resize(is:java.io.InputStream, maxWidth:Int, maxHeight:Int):BufferedImage = {
        val originalImage:BufferedImage = ImageIO.read(is)

        val height = originalImage.getHeight
        val width = originalImage.getWidth

        if (width <= maxWidth && height <= maxHeight)
            originalImage
        else {
            var scaledWidth:Int = width
            var scaledHeight:Int = height
            val ratio:Double = width/height
            if (scaledWidth > maxWidth){
                scaledWidth = maxWidth
                scaledHeight = (scaledWidth.doubleValue/ratio).intValue
            }
            if (scaledHeight > maxHeight){
                scaledHeight = maxHeight
                scaledWidth = (scaledHeight.doubleValue*ratio).intValue
            }
            val scaledBI = new BufferedImage(scaledWidth, scaledHeight,  BufferedImage.TYPE_INT_RGB)
            val g = scaledBI.createGraphics
            g.setComposite(AlphaComposite.Src)
            g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
            g.dispose
            scaledBI
        }
    }
}
like image 94
Jon Hoffman Avatar answered Nov 02 '22 09:11

Jon Hoffman


The other answer nicely describes how to resize the image and store a reference to the file on the file system.

If you want to use the lift mapper to store the actual file contents, you have to create your custom model object, and define a binary field on it. Try something like this:

package code {
package model {


import _root_.net.liftweb.mapper._
import _root_.net.liftweb.util._
import _root_.net.liftweb.common._


// singleton object which manipulates storing of Document instances
object Document extends Document with KeyedMetaMapper[Long, Document] {
}



class Document extends KeyedMapper[Long, Document] {
  def getSingleton = Document
  def primaryKeyField = id

  object id extends MappedLongIndex(this)

  object name extends MappedString(this, 20) {
    override def displayName = "Name"
    override def writePermission_? = true
  }

  object content extends MappedBinary(this) {
    override def displayName = "Content"
    override def writePermission_? = true
  }
}



}
}

Then, in bootstrap class, add this Document at the end:

Schemifier.schemify(true, Schemifier.infoF _, User, Document)

Voila. Using Document save (new Document) stores it into database. A new Document's fields can be set using the set method. Try playing with delete_!, find, findAll methods of the Document singleton to delete or find it in the database. It should be straightforward from this point on.

Finally, to display the image, you can override Lift's dispatching rules (in bootstrap class, Boot.scala). Try playing around with this example which overrides the rules for pdf requests:

def getFile(filename: String): Option[Document] = {
  val alldocs = Document.findAll()
  alldocs.find(_.name.get == filename)
}

LiftRules.statelessDispatchTable.append {
  case Req("file" :: name :: Nil, "pdf", GetRequest) =>
    () =>
    println("Got request for: " + name + ".pdf")
    for {
      stream <- tryo(
        getFile(name + ".pdf") map { 
          doc => new java.io.ByteArrayInputStream(doc.content.get)
        } getOrElse null
      )
      if null ne stream
    } yield StreamingResponse(stream,
                              () => stream.close,
                              stream.available,
                              List("Content-Type" -> "application/pdf"),
                              Nil,
                              200)
}
like image 25
axel22 Avatar answered Nov 02 '22 09:11

axel22