Browse Source

Started work on database integration. Cleaned up caching of thumbnails and improved performance of the thumb path method.

master
Drew Short 11 years ago
parent
commit
0fcad44e4e
  1. 53
      pom.xml
  2. 87
      src/main/resources/application.conf
  3. 34
      src/main/resources/hibernate.cfg.xml
  4. 23
      src/main/scala/com/sothr/imagetools/image/ImageService.scala
  5. 87
      src/test/resources/application.conf
  6. 7
      todo

53
pom.xml

@ -26,9 +26,6 @@
</pluginRepositories> </pluginRepositories>
<properties> <properties>
<project.version.major>0</project.version.major>
<project.version.minor>1</project.version.minor>
<project.version.tag>DEV</project.version.tag>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jdk.version>1.7</jdk.version> <jdk.version>1.7</jdk.version>
<lib.junit.version>3.8.1</lib.junit.version> <lib.junit.version>3.8.1</lib.junit.version>
@ -46,6 +43,8 @@
<lib.jtransforms.version>2.4.0</lib.jtransforms.version> <lib.jtransforms.version>2.4.0</lib.jtransforms.version>
<lib.typesafe-config.version>1.2.0</lib.typesafe-config.version> <lib.typesafe-config.version>1.2.0</lib.typesafe-config.version>
<lib.thumbnailator.version>[0.4, 0.5)</lib.thumbnailator.version> <lib.thumbnailator.version>[0.4, 0.5)</lib.thumbnailator.version>
<lib.h2database.version>1.3.175</lib.h2database.version>
<lib.hibernate.version>4.3.0.Final</lib.hibernate.version>
</properties> </properties>
<dependencies> <dependencies>
@ -62,19 +61,19 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${lib.logback.version}</version>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${lib.logback.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${lib.logback.version}</version>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${lib.logback.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>${lib.logback.version}</version>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>${lib.logback.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
@ -107,9 +106,9 @@
<version>${lib.jtransforms.version}</version> <version>${lib.jtransforms.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>${lib.commons-cli.version}</version>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>${lib.commons-cli.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-codec</groupId> <groupId>commons-codec</groupId>
@ -132,9 +131,24 @@
<version>${lib.akka.version}</version> <version>${lib.akka.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-slf4j_2.10</artifactId>
<version>${lib.akka.version}</version>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-slf4j_2.10</artifactId>
<version>${lib.akka.version}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${lib.h2database.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${lib.hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>${lib.hibernate.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
@ -337,6 +351,9 @@
<phase>process-resources</phase> <phase>process-resources</phase>
<configuration> <configuration>
<tasks> <tasks>
<copy todir="${basedir}/src/test/resources/hibernate">
<fileset dir="${basedir}/src/main/resources/hibernate" includes="**/*" />
</copy>
<copy file="${project.build.directory}/version.info" toFile="${basedir}/version.info" overwrite="true" /> <copy file="${project.build.directory}/version.info" toFile="${basedir}/version.info" overwrite="true" />
<copy file="${project.build.directory}/name.info" toFile="${basedir}/name.info" overwrite="true" /> <copy file="${project.build.directory}/name.info" toFile="${basedir}/name.info" overwrite="true" />
<copy file="${project.build.directory}/LICENSE" toFile="${basedir}/LICENSE" overwrite="true" /> <copy file="${project.build.directory}/LICENSE" toFile="${basedir}/LICENSE" overwrite="true" />

87
src/main/resources/application.conf

@ -8,48 +8,53 @@ akka {
//Default App Settings //Default App Settings
app { app {
version.current = "${build-version}"
timed = false
engine {
//Concurrency Settings
concurrent {
similarity.limit = 15
processing.limit = 15
}
version.current = "${build-version}"
timed = false
engine {
//Concurrency Settings
concurrent {
similarity.limit = 15
processing.limit = 15
} }
#Default Image Settings
image {
//images must be 90% similar
differenceThreshold = 0.90
//control generation of hashes for new images.
hash {
precision=64
}
ahash {
use = true
weight = 0.70
precision = 8
tolerence = 8
}
dhash {
use = true
weight = 0.85
precision = 8
tolerence = 8
}
phash {
//set to false if hashing images is taking too long
use = true
weight = 1.0
precision = 32
tolerence = 8
}
}
#Default Image Settings
image {
//images must be 90% similar
differenceThreshold = 0.90
//control generation of hashes for new images.
hash {
precision=64
} }
//Default Thumbnail Settings
thumbnail {
//Directory where to store thumbnails
directory = ".cache/thumbnails/"
//Size of the thumbnail to generate and store
size = 128
ahash {
use = true
weight = 0.70
precision = 8
tolerence = 8
} }
dhash {
use = true
weight = 0.85
precision = 8
tolerence = 8
}
phash {
//set to false if hashing images is taking too long
use = true
weight = 1.0
precision = 32
tolerence = 8
}
}
//Default Thumbnail Settings
thumbnail {
//Directory where to store thumbnails
directory = ".cache/thumbnails/"
//Size of the thumbnail to generate and store
size = 128
}
//Default Database Settings
database {
location = ".cache/database.db"
inMemory = false
}
} }

34
src/main/resources/hibernate.cfg.xml

@ -0,0 +1,34 @@
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!-- a SessionFactory instance listed as /jndi/name -->
<session-factory
name="java:hibernate/SessionFactory">
<!-- properties -->
<property name="connection.driver_class">org.h2.Driver</property>
<property name="connection.datasource">jdbc:h2:.cache/database.db</property>
<property name="dialect">org.hibernate.dialect.H2Dialect</property>
<property name="show_sql">false</property>
<property name="transaction.factory_class">
org.hibernate.transaction.JTATransactionFactory
</property>
<property name="jta.UserTransaction">java:comp/UserTransaction</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- mapping files -->
<!--<mapping resource="hibernate/"/>-->
<!-- cache settings -->
<!--<class-cache class="org.hibernate.auction.Item" usage="read-write"/>
<class-cache class="org.hibernate.auction.Bid" usage="read-only"/>
<collection-cache collection="org.hibernate.auction.Item.bids" usage="read-write"/>-->
</session-factory>
</hibernate-configuration>

23
src/main/scala/com/sothr/imagetools/image/ImageService.scala

@ -14,7 +14,6 @@ import com.sothr.imagetools.util.{PropertiesEnum, PropertiesService}
object ImageService extends Logging { object ImageService extends Logging {
val imageCache = AppConfig.cacheManager.getCache("images") val imageCache = AppConfig.cacheManager.getCache("images")
val thumbnailCache = AppConfig.cacheManager.getCache("thumbnails")
private def lookupImage(file:File):Image = { private def lookupImage(file:File):Image = {
var image:Image = null var image:Image = null
@ -45,7 +44,7 @@ object ImageService extends Logging {
val bufferedImage = ImageIO.read(file) val bufferedImage = ImageIO.read(file)
val hashes = HashService.getImageHashes(bufferedImage, file.getAbsolutePath) val hashes = HashService.getImageHashes(bufferedImage, file.getAbsolutePath)
var thumbnailPath = lookupThumbnailPath(hashes.md5) var thumbnailPath = lookupThumbnailPath(hashes.md5)
if (thumbnailPath == null) thumbnailPath = saveThumbnail(hashes.md5, getThumbnail(bufferedImage, hashes.md5))
if (thumbnailPath == null) thumbnailPath = getThumbnail(bufferedImage, hashes.md5)
val imageSize = { (bufferedImage.getWidth, bufferedImage.getHeight) } val imageSize = { (bufferedImage.getWidth, bufferedImage.getHeight) }
val image = new Image(file.getAbsolutePath, thumbnailPath, imageSize, hashes) val image = new Image(file.getAbsolutePath, thumbnailPath, imageSize, hashes)
debug(s"Created image: $image") debug(s"Created image: $image")
@ -61,8 +60,9 @@ object ImageService extends Logging {
def calculateThumbPath(md5:String):String = { def calculateThumbPath(md5:String):String = {
//break the path down into 4 char parts //break the path down into 4 char parts
val split:List[String] = md5.grouped(4).toList val split:List[String] = md5.grouped(4).toList
var path:String = PropertiesService.get(PropertiesEnum.ThumbnailDirectory.toString) + PropertiesService.get(PropertiesEnum.ThumbnailSize.toString) + "/"
for (seg <- split) path += seg + "/"
var dirPath = ""
for (seg <- split) dirPath += seg + "/"
var path:String = s"${PropertiesService.get(PropertiesEnum.ThumbnailDirectory.toString)}${PropertiesService.get(PropertiesEnum.ThumbnailSize.toString)}/$dirPath"
try { try {
val dir = new File(path) val dir = new File(path)
if (!dir.exists()) dir.mkdirs() if (!dir.exists()) dir.mkdirs()
@ -76,13 +76,6 @@ object ImageService extends Logging {
def lookupThumbnailPath(md5:String):String = { def lookupThumbnailPath(md5:String):String = {
var thumbPath:String = null var thumbPath:String = null
if (md5 != null) { if (md5 != null) {
//get from memory cache if possible
try {
if (thumbnailCache.isKeyInCache(md5)) thumbPath = thumbnailCache.get(md5).getObjectValue.asInstanceOf[String]
} catch {
case npe:NullPointerException => error(s"Error grabbing \'$md5\' from cache. thumbPath: \'$thumbPath\'", npe)
}
//get from datastore if possible
//check for the actual file //check for the actual file
val checkPath = calculateThumbPath(md5) val checkPath = calculateThumbPath(md5)
if (new File(checkPath).exists) thumbPath = checkPath if (new File(checkPath).exists) thumbPath = checkPath
@ -108,14 +101,6 @@ object ImageService extends Logging {
path path
} }
def saveThumbnail(md5:String, thumbnailPath:String):String = {
if (md5 == null || thumbnailPath == null) error(s"Error trying to save a md5: $md5 path: $thumbnailPath")
//save to cache
thumbnailCache.put(new Element(md5, thumbnailPath))
//save to datastore
thumbnailPath
}
/** /**
* Get the raw data for an image * Get the raw data for an image
*/ */

87
src/test/resources/application.conf

@ -8,48 +8,53 @@ akka {
//Default App Settings //Default App Settings
app { app {
version.current = "${build-version}"
timed = false
engine {
//Concurrency Settings
concurrent {
similarity.limit = 2
processing.limit = 2
}
version.current = "${build-version}"
timed = false
engine {
//Concurrency Settings
concurrent {
similarity.limit = 2
processing.limit = 2
} }
#Default Image Settings
image {
//images must be 90% similar
differenceThreshold = 0.90
//control generation of hashes for new images.
hash {
precision=64
}
ahash {
use = true
weight = 0.70
precision = 8
tolerence = 8
}
dhash {
use = true
weight = 0.85
precision = 8
tolerence = 8
}
phash {
//set to false if hashing images is taking too long
use = true
weight = 1.0
precision = 32
tolerence = 8
}
}
#Default Image Settings
image {
//images must be 90% similar
differenceThreshold = 0.90
//control generation of hashes for new images.
hash {
precision=64
} }
//Default Thumbnail Settings
thumbnail {
//Directory where to store thumbnails
directory = ".cache/thumbnails/"
//Size of the thumbnail to generate and store
size = 128
ahash {
use = true
weight = 0.70
precision = 8
tolerence = 8
} }
dhash {
use = true
weight = 0.85
precision = 8
tolerence = 8
}
phash {
//set to false if hashing images is taking too long
use = true
weight = 1.0
precision = 32
tolerence = 8
}
}
//Default Thumbnail Settings
thumbnail {
//Directory where to store thumbnails
directory = ".cache/thumbnails/"
//Size of the thumbnail to generate and store
size = 128
}
//Default Database Settings
database {
location = ".cache/database.db"
inMemory = false
}
} }

7
todo

@ -7,3 +7,10 @@ Add functionality to ImageService
Improve functionality of the PropertiesService Improve functionality of the PropertiesService
-Getters and Setters for sepcific values with proper cascading and type awareness -Getters and Setters for sepcific values with proper cascading and type awareness
-Nicer debugging? -Nicer debugging?
Hibernate - H2 intergration
- setup hibernate
- setup h2
- setup C3P0 connection pool
- transfer configuration files
- autoload configuration files?
- map DTO's
Loading…
Cancel
Save