提升图片上传、调整大小、存入数据库、显示

发布于 2024-08-04 04:42:03 字数 155 浏览 3 评论 0原文

是否有一个简洁的示例来说明如何上传图像、调整其大小、将其存储在数据库中,然后使用 Lift 提供图像?

我确信我可以将文件上传、Java 2D API、Lift Mapper 和 Response API 拼凑在一起。但是有没有我可以遵循的示例代码以“正确”或推荐的方式进行操作?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

水染的天色ゝ 2024-08-11 04:42:03

我通过创建一个新的 MappedField 来为链接到 s3 的 Mapper 字段执行此操作。我还有一些要调整大小的代码,但尚未测试或部署(因此请谨慎使用)。

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

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
        }
    }
}
疧_╮線 2024-08-11 04:42:03

另一个答案很好地描述了如何调整图像大小并在文件系统上存储对文件的引用。

如果您想使用 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
  }
}



}
}

然后,在引导类中,在末尾添加此 Document

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

瞧。使用文档保存(新文档)将其存储到数据库中。可以使用 set 方法设置新文档的字段。尝试使用 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)
}

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)
}
世界等同你 2024-08-11 04:42:03

根据乔恩霍夫曼接受的答案,我修复了错误。他的版本弄乱了纵横比(总是变成 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
    }
}

Based on the accepted answer by Jon Hoffman, I fixed the bugs. His version messes up the aspect ratio (it always becomes 1:1), because the math was off in a few spots. This version resizes big pictures until they fit, and respects the aspect ratio.

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
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文