提升图片上传,调整大小,存储到数据库中,显示。

9

有没有一个简洁的示例可以展示如何上传图像,调整其大小,将其存储在数据库中,然后使用Lift提供该图像?

我相信我可以从文件上传、Java 2D API、Lift Mapper和Response APIs中拼凑出来。但是是否有任何示例代码可以遵循以“正确”或推荐的方式执行操作?


2
不冒犯,但这听起来像是一个很好的项目,可以自己编写!它拥有一切:阴谋,冒险和SQL。 - user114600
是的,我本来就打算这么做!只是想在开始之前征求一下意见。 - Joe
3个回答

6
我为与s3相关联的映射器字段创建了一个新的MappedField。我还有一些调整大小的代码,但尚未测试或部署(因此请谨慎使用)。
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
        }
    }
}

错误的数学计算会破坏宽高比。我在三年后回答了一个修复版,但对于我使用正确的库来说,这仍然是非常有用的问题解答。 - Kajetan Abt

3
另一个答案很好地描述了如何调整图像大小并在文件系统上存储文件的引用。如果您想使用lift映射器来存储实际文件内容,则必须创建自定义模型对象,并在其上定义二进制字段。尝试像这样做:
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
  }
}



}
}

然后,在 bootstrap 类中,最后添加这个 Document
Schemifier.schemify(true, Schemifier.infoF _, User, Document)

使用Document save (new Document)将其存储到数据库中。可以使用set方法设置new Document的字段。尝试使用Document单例的delete_!findfindAll方法删除或在数据库中查找它,从此处开始应该很简单。

最后,要显示图像,您可以覆盖Lift的调度规则(在引导类Boot.scala中)。尝试使用此示例,覆盖pdf请求的规则:

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

2

基于Jon Hoffman所提供的答案,我修复了一些错误。他的版本会破坏图片的宽高比(它总是变成1:1),因为在一些地方数学计算有误。这个版本可以调整大图片的尺寸,直到它们适合,并保持它们的宽高比。

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

    var height = originalImage.getHeight
    var width = originalImage.getWidth

    // Shortcut to save a pointless reprocessing in case the image is small enough already
    if (width <= maxWidth && height <= maxHeight)
        originalImage
    else {          
        // If the picture was too big, it will either fit by width or height.
        // This essentially resizes the dimensions twice, until it fits
        if (width > maxWidth){
          height = (height.doubleValue() * (maxWidth.doubleValue() / width.doubleValue())).intValue
          width = maxWidth
        }
        if (height > maxHeight){
          width = (width.doubleValue() * (maxHeight.doubleValue() / height.doubleValue())).intValue
          height = maxHeight
        }
        val scaledBI = new BufferedImage(width, height,  BufferedImage.TYPE_INT_RGB)
        val g = scaledBI.createGraphics
        g.setComposite(AlphaComposite.Src)
        g.drawImage(originalImage, 0, 0, width, height, null);
        g.dispose
        scaledBI
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接