You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
5.5 KiB
155 lines
5.5 KiB
package com.sothr.imagetools.engine.image
|
|
|
|
import java.awt.image.BufferedImage
|
|
import java.io.{File, IOException}
|
|
import javax.imageio.ImageIO
|
|
|
|
import com.sothr.imagetools.engine.AppConfig
|
|
import com.sothr.imagetools.engine.dao.ImageDAO
|
|
import com.sothr.imagetools.engine.util.{PropertiesService, PropertyEnum}
|
|
import com.sothr.imagetools.engine.vo.ImageHashVO
|
|
import com.sothr.imagetools.hash.{HashService, ImageHash}
|
|
import com.sothr.imagetools.hash.util.ImageUtil
|
|
import grizzled.slf4j.Logging
|
|
import net.sf.ehcache.Element
|
|
import org.hibernate.HibernateException
|
|
|
|
object ImageService extends Logging {
|
|
|
|
val imageCache = AppConfig.cacheManager.getCache("images")
|
|
private val imageDAO = new ImageDAO()
|
|
|
|
def getImage(file: File): Image = {
|
|
try {
|
|
val image = lookupImage(file)
|
|
if (image != null) {
|
|
debug(s"${file.getAbsolutePath} was already processed")
|
|
return image
|
|
} else {
|
|
debug(s"Processing image: ${file.getAbsolutePath}")
|
|
val bufferedImage = ImageIO.read(file)
|
|
val hashes = HashService.getImageHashes(
|
|
PropertiesService.aHashSettings,
|
|
PropertiesService.dHashSettings,
|
|
PropertiesService.pHashSettings,
|
|
bufferedImage,
|
|
file.getAbsolutePath)
|
|
|
|
var thumbnailPath = lookupThumbnailPath(hashes.fileHash)
|
|
if (thumbnailPath == null) thumbnailPath = getThumbnail(bufferedImage, hashes.fileHash)
|
|
val imageSize = {
|
|
(bufferedImage.getWidth, bufferedImage.getHeight)
|
|
}
|
|
val image = new Image(file.getAbsolutePath, thumbnailPath, imageSize, ImageService.convertToImageHashVO(hashes))
|
|
debug(s"Created image: $image")
|
|
return saveImage(image)
|
|
}
|
|
} catch {
|
|
case ioe: IOException => error(s"Error processing ${file.getAbsolutePath}... ${ioe.getMessage}")
|
|
case ex: Exception => error(s"Error processing ${file.getAbsolutePath}... ${ex.getMessage}", ex)
|
|
}
|
|
null
|
|
}
|
|
|
|
def convertToImageHashDTO(imageHashVO: ImageHashVO): ImageHash = {
|
|
new ImageHash(imageHashVO.ahash, imageHashVO.dhash, imageHashVO.phash, imageHashVO.fileHash)
|
|
}
|
|
|
|
def convertToImageHashVO(imageHashDTO: ImageHash): ImageHashVO = {
|
|
new ImageHashVO(imageHashDTO.ahash, imageHashDTO.dhash, imageHashDTO.phash, imageHashDTO.fileHash)
|
|
}
|
|
|
|
private def lookupImage(file: File): Image = {
|
|
var image: Image = null
|
|
var found = false
|
|
//get from memory cache if possible
|
|
try {
|
|
if (imageCache.isKeyInCache(file.getAbsolutePath)) {
|
|
image = imageCache.get(file.getAbsolutePath).getObjectValue.asInstanceOf[Image]
|
|
found = true
|
|
}
|
|
} catch {
|
|
case npe: NullPointerException => debug(s"\'${file.getAbsolutePath}\' was supposed to be in the cache, but was not")
|
|
}
|
|
//get from datastore if possible
|
|
if (!found) {
|
|
try {
|
|
val tempImage = imageDAO.find(file.getAbsolutePath)
|
|
if (tempImage != null) image = tempImage
|
|
} catch {
|
|
case ex: Exception => error(s"Error looking up \'${file.getAbsolutePath}\' was supposed to be in the database, but was not", ex)
|
|
}
|
|
}
|
|
image
|
|
}
|
|
|
|
private def saveImage(image: Image): Image = {
|
|
//save to cache
|
|
imageCache.put(new Element(image.imagePath, image))
|
|
//save to datastore
|
|
try {
|
|
imageDAO.save(image)
|
|
} catch {
|
|
case ex: Exception => error(s"Error saving \'${image.imagePath}\' to database", ex)
|
|
}
|
|
image
|
|
}
|
|
|
|
def lookupThumbnailPath(md5: String): String = {
|
|
var thumbPath: String = null
|
|
if (md5 != null) {
|
|
//check for the actual file
|
|
val checkPath = calculateThumbPath(md5)
|
|
if (new File(checkPath).exists) thumbPath = checkPath
|
|
} else {
|
|
error("Null md5 passed in")
|
|
}
|
|
thumbPath
|
|
}
|
|
|
|
def calculateThumbPath(md5: String): String = {
|
|
//break the path down into 4 char parts
|
|
val subPath = md5.substring(0, 3)
|
|
var path: String = s"${PropertiesService.get(PropertyEnum.ThumbnailDirectory.toString)}${PropertiesService.get(PropertyEnum.ThumbnailSize.toString)}/$subPath/"
|
|
try {
|
|
val dir = new File(path)
|
|
if (!dir.exists()) dir.mkdirs()
|
|
} catch {
|
|
case ioe: IOException => error(s"Unable to create dirs for path: \'$path\'", ioe)
|
|
}
|
|
path += md5 + ".jpg"
|
|
path
|
|
}
|
|
|
|
def getThumbnail(image: BufferedImage, md5: String): String = {
|
|
//create thumbnail
|
|
val thumb = ImageUtil.resize(image, PropertiesService.get(PropertyEnum.ThumbnailSize.toString).toInt, forced = false)
|
|
//calculate path
|
|
val path = calculateThumbPath(md5)
|
|
// save thumbnail to path
|
|
try {
|
|
ImageIO.write(thumb, "png", new File(path))
|
|
debug(s"Wrote thumbnail to $path")
|
|
} catch {
|
|
case ioe: IOException => error(s"Unable to save thumbnail to $path", ioe)
|
|
}
|
|
// return path
|
|
path
|
|
}
|
|
|
|
def deleteImage(image: Image) = {
|
|
debug(s"Attempting to delete all traces of image: ${image.getImagePath}")
|
|
try {
|
|
val imageFile = new File(image.imagePath)
|
|
//try to delete the file
|
|
imageFile.delete()
|
|
//purge the file from the database and cache
|
|
this.imageCache.remove(imageFile.getAbsolutePath)
|
|
this.imageDAO.delete(image)
|
|
} catch {
|
|
case se: SecurityException => error(s"Unable to delete file: ${image.getImagePath} due to a security exception", se)
|
|
case ise: IllegalStateException => error(s"Unable to delete file: ${image.getImagePath} due to an illegal state exception", ise)
|
|
case he: HibernateException => error(s"Unable to delete file: ${image.getImagePath} due to a hibernate exception", he)
|
|
}
|
|
}
|
|
}
|