Soulever le téléchargement des images, redimensionner, stocker dans la base de données, afficher

StackOverflow https://stackoverflow.com/questions/1404814

Question

Existe-t-il un exemple succinct de la façon de télécharger une image, de la redimensionner, de la stocker dans une base de données, puis de diffuser l'image avec Lift?

Je suis sûr que je pourrais le rassembler à partir des API de téléchargement de fichier, d'API Java 2D, de mappeur d'élévation et de réponse. Mais y a-t-il un exemple de code que je peux suivre pour le faire de manière "correcte" ou recommandée?

Était-ce utile?

La solution

Je l'ai fait pour un champ Mapper lié à s3 en créant un nouveau MappedField. J'ai aussi un code à redimensionner, mais je n'ai pas encore testé ni déployé (utilisez-le avec prudence).

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

Autres conseils

L’autre réponse explique bien comment redimensionner l’image et stocker une référence au fichier dans le système de fichiers.

Si vous souhaitez utiliser le mappeur d'ascenseurs pour stocker le contenu réel du fichier, vous devez créer votre objet modèle personnalisé et définir un champ binaire sur celui-ci. Essayez quelque chose comme ça:

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



}
}

Ensuite, dans la classe bootstrap, ajoutez ce Document à la fin:

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

Voila. Utiliser Document save (nouveau document) le stocke dans la base de données. Les champs d'un nouveau document peuvent être définis à l'aide de la méthode set . Essayez de jouer avec delete _! , trouver , méthodes findAll du singleton Document à supprimer ou à rechercher dans la base de données. . Cela devrait être simple à partir de maintenant.

Enfin, pour afficher l'image, vous pouvez remplacer les règles de répartition de Lift (dans la classe bootstrap, Boot.scala). Essayez de vous amuser avec cet exemple, qui remplace les règles applicables aux requêtes 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)
}

Sur la base de la réponse acceptée par Jon Hoffman, j’ai corrigé les bugs. Sa version gâche le rapport d'aspect (il devient toujours 1: 1), parce que le calcul était erroné à quelques endroits près. Cette version redimensionne les grandes images jusqu’à leur adaptation et respecte le rapport de format.

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
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top