diff --git a/pom.xml b/pom.xml
index d89afab..792541b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,12 +28,13 @@
UTF-8
1.8
+ 2.11
+ 2.11.2
4.11
2.2.1
1.1.2
1.7.7
1.0.2
- 2.11.2
2.3.5
1.1
2.8.0
@@ -46,6 +47,7 @@
4.3.0.Final
2.6.6
2.2-cj-1.0
+ 1.4
@@ -57,7 +59,7 @@
org.scalatest
- scalatest_2.11
+ scalatest_${scala.binary.version}
${lib.scalatest.version}
test
@@ -83,7 +85,7 @@
org.clapper
- grizzled-slf4j_2.11
+ grizzled-slf4j_${scala.binary.version}
${lib.grizzled-slf4j.version}
@@ -133,7 +135,7 @@
com.typesafe.akka
- akka-slf4j_2.11
+ akka-slf4j_${scala.binary.version}
${lib.akka.version}
@@ -166,6 +168,11 @@
markdown4j
${lib.markdown4j.version}
+
+ com.jsuereth
+ scala-arm_${scala.binary.version}
+ ${lib.scala-arm.version}
+
diff --git a/src/includes/LICENSE b/src/includes/LICENSE
index c969132..0dcd862 100644
--- a/src/includes/LICENSE
+++ b/src/includes/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2013 Drew Short
+Copyright (c) 2014 Drew Short
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
diff --git a/src/main/java/com/sothr/imagetools/AppCLI.java b/src/main/java/com/sothr/imagetools/AppCLI.java
index e18f27d..7c63604 100644
--- a/src/main/java/com/sothr/imagetools/AppCLI.java
+++ b/src/main/java/com/sothr/imagetools/AppCLI.java
@@ -3,6 +3,9 @@ package com.sothr.imagetools;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
+import com.sothr.imagetools.engine.CLIEngineListener;
+import com.sothr.imagetools.engine.ConcurrentEngine;
+import com.sothr.imagetools.engine.Engine;
import com.sothr.imagetools.image.SimilarImages;
import org.apache.commons.cli.*;
import org.slf4j.Logger;
diff --git a/src/main/java/com/sothr/imagetools/AppConfig.java b/src/main/java/com/sothr/imagetools/AppConfig.java
index f98d987..be8ddf6 100644
--- a/src/main/java/com/sothr/imagetools/AppConfig.java
+++ b/src/main/java/com/sothr/imagetools/AppConfig.java
@@ -1,23 +1,19 @@
package com.sothr.imagetools;
import akka.actor.ActorSystem;
-import com.sothr.imagetools.dao.HibernateUtil;
-import com.sothr.imagetools.util.ResourceLoader;
-import com.sothr.imagetools.util.PropertiesService;
-import com.sothr.imagetools.util.PropertiesEnum;
-import javafx.stage.Stage;
-import net.sf.ehcache.CacheManager;
-
-import org.slf4j.LoggerFactory;
-
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;
+import com.sothr.imagetools.dao.HibernateUtil;
+import com.sothr.imagetools.util.PropertiesService;
+import com.sothr.imagetools.util.ResourceLoader;
+import javafx.stage.Stage;
+import net.sf.ehcache.CacheManager;
+import org.slf4j.LoggerFactory;
import java.io.File;
-import java.util.Properties;
public class AppConfig {
@@ -37,7 +33,7 @@ public class AppConfig {
private static Boolean configuredCache = false;
// General Akka Actor System
- private static ActorSystem appSystem = ActorSystem.create("ITActorSystem");
+ private static final ActorSystem appSystem = ActorSystem.create("ITActorSystem");
// The Main App
private static Stage primaryStage = null;
@@ -55,7 +51,7 @@ public class AppConfig {
configCache();
}
- public static void configLogging(String location) {
+ private static void configLogging(String location) {
//Logging Config
//remove previous configuration if it exists
Logger rootLogger = (Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
@@ -91,11 +87,11 @@ public class AppConfig {
}
String message = fromFile ? "From File" : "From Defaults";
logger.info(String.format("Configured Logger %s", message));
- logger.info("Detected Version: %s of Image Tools".format(PropertiesService.getVersion().toString()));
+ logger.info(String.format("Detected Version: %s of Image Tools", PropertiesService.getVersion().toString()));
}
//Only configure logging from the default file once
- public static void configLogging() {
+ private static void configLogging() {
if (!configuredLogging) {
configLogging(LOGSETTINGSFILE);
configuredLogging = true;
@@ -103,7 +99,7 @@ public class AppConfig {
}
}
- public static void loadProperties() {
+ private static void loadProperties() {
if (!loadedProperties) {
File file = new File(USERPROPERTIESFILE);
if (file.exists()) {
@@ -116,7 +112,7 @@ public class AppConfig {
}
}
- public static void configCache() {
+ private static void configCache() {
if (!configuredCache) {
cacheManager = CacheManager.newInstance();
configuredCache = true;
@@ -129,7 +125,7 @@ public class AppConfig {
HibernateUtil.getSessionFactory().close();
}
- public static void saveProperties() {
+ private static void saveProperties() {
PropertiesService.saveConf(USERPROPERTIESFILE);
logger.debug("Saved properties");
}
diff --git a/src/main/java/com/sothr/imagetools/errors/ImageToolsException.java b/src/main/java/com/sothr/imagetools/errors/ImageToolsException.java
index b935788..e7bb3d1 100644
--- a/src/main/java/com/sothr/imagetools/errors/ImageToolsException.java
+++ b/src/main/java/com/sothr/imagetools/errors/ImageToolsException.java
@@ -1,6 +1,8 @@
package com.sothr.imagetools.errors;
/**
+ * Simple Exception
+ *
* Created by drew on 12/31/13.
*/
public class ImageToolsException extends Exception {
diff --git a/src/main/java/com/sothr/imagetools/util/ResourceLoader.java b/src/main/java/com/sothr/imagetools/util/ResourceLoader.java
index 04783f3..e480d7a 100644
--- a/src/main/java/com/sothr/imagetools/util/ResourceLoader.java
+++ b/src/main/java/com/sothr/imagetools/util/ResourceLoader.java
@@ -2,17 +2,20 @@ package com.sothr.imagetools.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
import java.io.InputStream;
import java.net.URL;
/**
+ * Seamlessly handle resource loading
+ *
* Created by drew on 1/5/14.
*/
public class ResourceLoader {
private static final ResourceLoader instance = new ResourceLoader();
- private Logger logger = LoggerFactory.getLogger(this.getClass());
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
private ResourceLoader() {
logger.info("Created Resource Loader");
diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf
index 73c3060..420807b 100644
--- a/src/main/resources/application.conf
+++ b/src/main/resources/application.conf
@@ -29,20 +29,20 @@ app {
use = true
weight = 0.70
precision = 8
- tolerence = 8
+ tolerance = 8
}
dhash {
use = true
weight = 0.85
precision = 8
- tolerence = 8
+ tolerance = 8
}
phash {
//set to false if hashing images is taking too long
use = true
weight = 1.0
precision = 32
- tolerence = 8
+ tolerance = 8
}
}
//Default Thumbnail Settings
diff --git a/src/main/resources/ehcache.xml b/src/main/resources/ehcache.xml
index 705dd72..08679a7 100644
--- a/src/main/resources/ehcache.xml
+++ b/src/main/resources/ehcache.xml
@@ -1,4 +1,5 @@
+
diff --git a/src/main/resources/fxml/mainapp/MainApp.fxml b/src/main/resources/fxml/mainapp/MainApp.fxml
index 43007f0..f9811fc 100644
--- a/src/main/resources/fxml/mainapp/MainApp.fxml
+++ b/src/main/resources/fxml/mainapp/MainApp.fxml
@@ -1,11 +1,10 @@
-
+
-
-
+
@@ -62,8 +61,12 @@
-
-
+
+
@@ -110,7 +113,7 @@
-
+
diff --git a/src/main/scala/com/sothr/imagetools/dao/HibernateUtil.scala b/src/main/scala/com/sothr/imagetools/dao/HibernateUtil.scala
index 862f22a..1997537 100644
--- a/src/main/scala/com/sothr/imagetools/dao/HibernateUtil.scala
+++ b/src/main/scala/com/sothr/imagetools/dao/HibernateUtil.scala
@@ -1,25 +1,31 @@
package com.sothr.imagetools.dao
+import com.sothr.imagetools.util.{PropertiesService, PropertyEnum}
import grizzled.slf4j.Logging
import org.hibernate.SessionFactory
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder
import org.hibernate.cfg.Configuration
-import com.sothr.imagetools.util.{PropertiesEnum, PropertiesService}
+import org.hibernate.service.ServiceRegistry
/**
+ * Utility class to interface with hibernate
+ *
* Created by drew on 2/8/14.
*/
object HibernateUtil extends Logging {
private val sessionFactory:SessionFactory = buildSessionFactory()
+ private var serviceRegistry:ServiceRegistry = null
private def buildSessionFactory():SessionFactory = {
try {
// Create the SessionFactory from hibernate.cfg.xml
val configuration = new Configuration().configure("hibernate.cfg.xml")
//set the database location
- info(s"Connecting to database at: \'${PropertiesService.get(PropertiesEnum.DatabaseConnectionURL.toString)}\'")
- configuration.setProperty("hibernate.connection.url", PropertiesService.get(PropertiesEnum.DatabaseConnectionURL.toString))
- return configuration.buildSessionFactory
+ info(s"Connecting to database at: \'${PropertiesService.get(PropertyEnum.DatabaseConnectionURL.toString)}\'")
+ configuration.setProperty("hibernate.connection.url", PropertiesService.get(PropertyEnum.DatabaseConnectionURL.toString))
+ serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties).build
+ configuration.buildSessionFactory(serviceRegistry)
} catch {
case ex:Throwable =>
// Make sure you log the exception, as it might be swallowed
@@ -28,7 +34,7 @@ object HibernateUtil extends Logging {
}
}
- def getSessionFactory():SessionFactory = {
+ def getSessionFactory:SessionFactory = {
sessionFactory
}
diff --git a/src/main/scala/com/sothr/imagetools/dao/ImageDAO.scala b/src/main/scala/com/sothr/imagetools/dao/ImageDAO.scala
index 4bc530f..dc1761a 100644
--- a/src/main/scala/com/sothr/imagetools/dao/ImageDAO.scala
+++ b/src/main/scala/com/sothr/imagetools/dao/ImageDAO.scala
@@ -1,14 +1,16 @@
package com.sothr.imagetools.dao
-import org.hibernate.{Session, SessionFactory}
import com.sothr.imagetools.image.Image
+import org.hibernate.{Session, SessionFactory}
/**
+ * Interact with stored images
+ *
* Created by drew on 2/8/14.
*/
class ImageDAO {
- private val sessionFactory:SessionFactory = HibernateUtil.getSessionFactory()
+ private val sessionFactory:SessionFactory = HibernateUtil.getSessionFactory
def find(path:String):Image = {
val session:Session = sessionFactory.getCurrentSession
diff --git a/src/main/scala/com/sothr/imagetools/dto/ImageHashDTO.scala b/src/main/scala/com/sothr/imagetools/dto/ImageHashDTO.scala
index 9e40f7e..b465029 100644
--- a/src/main/scala/com/sothr/imagetools/dto/ImageHashDTO.scala
+++ b/src/main/scala/com/sothr/imagetools/dto/ImageHashDTO.scala
@@ -1,8 +1,9 @@
package com.sothr.imagetools.dto
-import grizzled.slf4j.Logging
import javax.persistence._
+import grizzled.slf4j.Logging
+
@Entity
@Table(name = "ImageHash")
class ImageHashDTO(var ahash:Long, var dhash:Long, var phash:Long, var md5:String) extends Serializable with Logging {
diff --git a/src/main/scala/com/sothr/imagetools/ConcurrentEngine.scala b/src/main/scala/com/sothr/imagetools/engine/ConcurrentEngine.scala
similarity index 94%
rename from src/main/scala/com/sothr/imagetools/ConcurrentEngine.scala
rename to src/main/scala/com/sothr/imagetools/engine/ConcurrentEngine.scala
index 729934f..ea08b21 100644
--- a/src/main/scala/com/sothr/imagetools/ConcurrentEngine.scala
+++ b/src/main/scala/com/sothr/imagetools/engine/ConcurrentEngine.scala
@@ -1,18 +1,18 @@
-package com.sothr.imagetools
+package com.sothr.imagetools.engine
import java.io.File
+import java.util.concurrent.TimeUnit
+
import akka.actor._
-import akka.routing.{Broadcast, RoundRobinRouter, SmallestMailboxRouter}
import akka.pattern.ask
+import akka.routing.{Broadcast, RoundRobinRouter, SmallestMailboxRouter}
import akka.util.Timeout
-import java.util.concurrent.TimeUnit
-import com.sothr.imagetools.image.{SimilarImages, Image}
import com.sothr.imagetools.hash.HashService
-import com.sothr.imagetools.util.{PropertiesEnum, PropertiesService}
-import scala.concurrent.Await
-import java.lang.Thread
+import com.sothr.imagetools.image.{Image, ImageService, SimilarImages}
+import com.sothr.imagetools.util._
+
import scala.collection.mutable
-import akka.routing.Broadcast
+import scala.concurrent.Await
class ConcurrentEngine extends Engine with grizzled.slf4j.Logging {
val engineProcessingController = system.actorOf(Props[ConcurrentEngineProcessingController], name = "EngineProcessingController")
@@ -127,7 +127,7 @@ case object EngineActorReactivate
class ConcurrentEngineProcessingController extends Actor with ActorLogging {
val numOfRouters = {
- val max = PropertiesService.get(PropertiesEnum.ConcurrentProcessingLimit.toString).toInt
+ val max = PropertiesService.get(PropertyEnum.ConcurrentProcessingLimit.toString).toInt
val processors = Runtime.getRuntime.availableProcessors()
var threads = 0
if (processors > max) threads = max else if (processors > 1) threads = processors - 1 else threads = 1
@@ -161,8 +161,8 @@ class ConcurrentEngineProcessingController extends Actor with ActorLogging {
case command:EngineFileProcessed => fileProcessed(command)
case EngineNoMoreFiles => requestWrapup()
case EngineActorProcessingFinished => actorProcessingFinished()
- case EngineIsProcessingFinished => isProcessingFinished()
- case EngineGetProcessingResults => getResults()
+ case EngineIsProcessingFinished => checkIfProcessingIsFinished()
+ case EngineGetProcessingResults => checkForResults()
case _ => log.info("received unknown message")
}
@@ -203,7 +203,7 @@ class ConcurrentEngineProcessingController extends Actor with ActorLogging {
/*
* Check if processing is done
*/
- def isProcessingFinished() = {
+ def checkIfProcessingIsFinished() = {
try {
if (processorsFinished >= numOfRouters) sender ! true else sender ! false
} catch {
@@ -216,7 +216,7 @@ class ConcurrentEngineProcessingController extends Actor with ActorLogging {
/*
* Get the results of the processing
*/
- def getResults() = {
+ def checkForResults() = {
try {
processorsFinished = 0
toProcess = 0
@@ -269,7 +269,7 @@ case object EngineActorCompareImagesFinished
class ConcurrentEngineSimilarityController extends Actor with ActorLogging {
val numOfRouters = {
- val max = PropertiesService.get(PropertiesEnum.ConcurrentSimiliartyLimit.toString).toInt
+ val max = PropertiesService.get(PropertyEnum.ConcurrentSimilarityLimit.toString).toInt
val processors = Runtime.getRuntime.availableProcessors()
var threads = 0
if (processors > max) threads = max else if (processors > 1) threads = processors - 1 else threads = 1
@@ -304,8 +304,8 @@ class ConcurrentEngineSimilarityController extends Actor with ActorLogging {
case command:EngineCompareImagesComplete => similarityProcessed(command)
case EngineNoMoreComparisons => requestWrapup()
case EngineActorCompareImagesFinished => actorProcessingFinished()
- case EngineIsSimilarityFinished => isProcessingFinished()
- case EngineGetSimilarityResults => getResults()
+ case EngineIsSimilarityFinished => checkIfProcessingIsFinished()
+ case EngineGetSimilarityResults => checkForResults()
case _ => log.info("received unknown message")
}
@@ -352,7 +352,7 @@ class ConcurrentEngineSimilarityController extends Actor with ActorLogging {
/*
* Check if processing is done
*/
- def isProcessingFinished() = {
+ def checkIfProcessingIsFinished() = {
try {
log.debug("Processors Finished {}/{}", processorsFinished, numOfRouters)
if (processorsFinished >= numOfRouters) sender ! true else sender ! false
@@ -366,7 +366,7 @@ class ConcurrentEngineSimilarityController extends Actor with ActorLogging {
/*
* Get the results of the processing
*/
- def getResults() = {
+ def checkForResults() = {
try {
processorsFinished = 0
toProcess = 0
diff --git a/src/main/scala/com/sothr/imagetools/Engine.scala b/src/main/scala/com/sothr/imagetools/engine/Engine.scala
similarity index 91%
rename from src/main/scala/com/sothr/imagetools/Engine.scala
rename to src/main/scala/com/sothr/imagetools/engine/Engine.scala
index 20c5eef..a72fcf5 100644
--- a/src/main/scala/com/sothr/imagetools/Engine.scala
+++ b/src/main/scala/com/sothr/imagetools/engine/Engine.scala
@@ -1,13 +1,18 @@
-package com.sothr.imagetools
+package com.sothr.imagetools.engine
-import com.sothr.imagetools.image.{SimilarImages, ImageFilter, Image}
-import com.sothr.imagetools.util.DirectoryFilter
-import scala.collection.mutable
import java.io.File
+
+import akka.actor.{Actor, ActorLogging, ActorRef, ActorSystem}
+import com.sothr.imagetools.AppConfig
+import com.sothr.imagetools.image.{Image, ImageFilter, SimilarImages}
+import com.sothr.imagetools.util.DirectoryFilter
import grizzled.slf4j.Logging
-import akka.actor.{ActorRef, ActorSystem, ActorLogging, Actor}
+
+import scala.collection.mutable
/**
+ * Engine definition
+ *
* Created by drew on 1/26/14.
*/
abstract class Engine extends Logging {
@@ -44,12 +49,12 @@ abstract class Engine extends Logging {
/**
* Get all images for a directory with hashes
*/
- def getImagesForDirectory(directoryPath:String, recursive:Boolean=false, recursiveDepth:Int=500):List[Image];
+ def getImagesForDirectory(directoryPath:String, recursive:Boolean=false, recursiveDepth:Int=500):List[Image]
/**
* Get all similar images for a directory with hashes
*/
- def getSimilarImagesForDirectory(directoryPath:String, recursive:Boolean=false, recursiveDepth:Int=500):List[SimilarImages];
+ def getSimilarImagesForDirectory(directoryPath:String, recursive:Boolean=false, recursiveDepth:Int=500):List[SimilarImages]
}
case class SubmitMessage(message:String)
diff --git a/src/main/scala/com/sothr/imagetools/SequentialEngine.scala b/src/main/scala/com/sothr/imagetools/engine/SequentialEngine.scala
similarity index 94%
rename from src/main/scala/com/sothr/imagetools/SequentialEngine.scala
rename to src/main/scala/com/sothr/imagetools/engine/SequentialEngine.scala
index 48133a0..5ea0a3c 100644
--- a/src/main/scala/com/sothr/imagetools/SequentialEngine.scala
+++ b/src/main/scala/com/sothr/imagetools/engine/SequentialEngine.scala
@@ -1,12 +1,17 @@
-package com.sothr.imagetools
+package com.sothr.imagetools.engine
-import com.sothr.imagetools.image.{SimilarImages, ImageFilter, Image}
-import scala.collection.mutable
import java.io.File
-import grizzled.slf4j.Logging
+
import akka.actor.{ActorRef, Props}
+import com.sothr.imagetools.image.{Image, ImageService, SimilarImages}
+import grizzled.slf4j.Logging
+
+import scala.collection.mutable
/**
+ * Engine that works sequentially
+ * Very Slow, but consistent. Excellent for testing
+ *
* Created by drew on 1/26/14.
*/
class SequentialEngine extends Engine with Logging {
diff --git a/src/main/scala/com/sothr/imagetools/hash/DHash.scala b/src/main/scala/com/sothr/imagetools/hash/DHash.scala
index 91bec21..2a0c595 100644
--- a/src/main/scala/com/sothr/imagetools/hash/DHash.scala
+++ b/src/main/scala/com/sothr/imagetools/hash/DHash.scala
@@ -3,7 +3,9 @@ package com.sothr.imagetools.hash
import grizzled.slf4j.Logging
/**
- * Created by dev on 1/22/14.
+ * DHash algorithm class
+ *
+ * Created by Drew on 1/22/14.
*/
object DHash extends PerceptualHasher with Logging {
def getHash(imageData: Array[Array[Int]]): Long = {
diff --git a/src/main/scala/com/sothr/imagetools/hash/HashService.scala b/src/main/scala/com/sothr/imagetools/hash/HashService.scala
index acda243..b945656 100644
--- a/src/main/scala/com/sothr/imagetools/hash/HashService.scala
+++ b/src/main/scala/com/sothr/imagetools/hash/HashService.scala
@@ -1,14 +1,15 @@
package com.sothr.imagetools.hash
-import grizzled.slf4j.Logging
-import com.sothr.imagetools.dto.ImageHashDTO
-import com.sothr.imagetools.util.{PropertiesEnum, PropertiesService, Hamming}
-import com.sothr.imagetools.ImageService
import java.awt.image.BufferedImage
+import java.io.{File, FileInputStream}
import javax.imageio.ImageIO
-import java.io.{FileInputStream, File}
+
+import com.sothr.imagetools.dto.ImageHashDTO
+import com.sothr.imagetools.image.ImageService
+import com.sothr.imagetools.util.{Hamming, PropertiesService}
+import grizzled.slf4j.Logging
import org.apache.commons.codec.digest.DigestUtils
-import com.sothr.imagetools.image.Image
+import resource._
/**
* A service that exposes the ability to construct perceptive hashes from an
@@ -33,14 +34,14 @@ object HashService extends Logging {
//Get Image Data
val grayImage = ImageService.convertToGray(image)
- if (PropertiesService.useAhash == true) {
- ahash = getAhash(grayImage, true)
+ if (PropertiesService.useAhash) {
+ ahash = getAhash(grayImage, alreadyGray = true)
}
- if (PropertiesService.useDhash == true) {
- dhash = getDhash(grayImage, true)
+ if (PropertiesService.useDhash) {
+ dhash = getDhash(grayImage, alreadyGray = true)
}
- if (PropertiesService.usePhash == true) {
- phash = getPhash(grayImage, true)
+ if (PropertiesService.usePhash) {
+ phash = getPhash(grayImage, alreadyGray = true)
}
val hashes = new ImageHashDTO(ahash, dhash, phash, md5)
@@ -57,7 +58,7 @@ object HashService extends Logging {
} else {
grayImage = ImageService.convertToGray(image)
}
- val resizedImage = ImageService.resize(grayImage, PropertiesService.aHashPrecision, true)
+ val resizedImage = ImageService.resize(grayImage, PropertiesService.aHashPrecision, forced = true)
val imageData = ImageService.getImageData(resizedImage)
AHash.getHash(imageData)
}
@@ -70,7 +71,7 @@ object HashService extends Logging {
} else {
grayImage = ImageService.convertToGray(image)
}
- val resizedImage = ImageService.resize(grayImage, PropertiesService.dHashPrecision, true)
+ val resizedImage = ImageService.resize(grayImage, PropertiesService.dHashPrecision, forced = true)
val imageData = ImageService.getImageData(resizedImage)
DHash.getHash(imageData)
}
@@ -83,13 +84,16 @@ object HashService extends Logging {
} else {
grayImage = ImageService.convertToGray(image)
}
- val resizedImage = ImageService.resize(grayImage, PropertiesService.pHashPrecision, true)
+ val resizedImage = ImageService.resize(grayImage, PropertiesService.pHashPrecision, forced = true)
val imageData = ImageService.getImageData(resizedImage)
PHash.getHash(imageData)
}
def getMD5(filePath:String):String = {
- DigestUtils.md5Hex(new FileInputStream(filePath))
+ managed(new FileInputStream(filePath)) acquireAndGet {
+ input =>
+ DigestUtils.md5Hex(input)
+ }
}
def areAhashSimilar(ahash1:Long, ahash2:Long):Boolean = {
diff --git a/src/main/scala/com/sothr/imagetools/hash/PerceptualHasher.scala b/src/main/scala/com/sothr/imagetools/hash/PerceptualHasher.scala
index e1423a8..08280ea 100644
--- a/src/main/scala/com/sothr/imagetools/hash/PerceptualHasher.scala
+++ b/src/main/scala/com/sothr/imagetools/hash/PerceptualHasher.scala
@@ -1,7 +1,9 @@
package com.sothr.imagetools.hash
/**
- * Created by dev on 1/22/14.
+ * Interface for perceptual hashing
+ *
+ * Created by drew on 1/22/14.
*/
trait PerceptualHasher {
diff --git a/src/main/scala/com/sothr/imagetools/image/Image.scala b/src/main/scala/com/sothr/imagetools/image/Image.scala
index 21fd3b6..0168fb8 100644
--- a/src/main/scala/com/sothr/imagetools/image/Image.scala
+++ b/src/main/scala/com/sothr/imagetools/image/Image.scala
@@ -1,9 +1,10 @@
package com.sothr.imagetools.image
+import javax.persistence._
+
import com.sothr.imagetools.dto.ImageHashDTO
import com.sothr.imagetools.hash.HashService
import grizzled.slf4j.Logging
-import javax.persistence._
@Entity
@Table(name = "Image")
@@ -36,7 +37,7 @@ class Image(val image:String, val thumbnail:String, val size:(Int, Int), val ima
var imageType:ImageType = ImageType.SingleFrameImage
- def getName():String = {
+ def getName:String = {
if(this.imageName.length < 1) {
this.imageName = this.getImagePath.split('/').last
}
@@ -57,7 +58,7 @@ class Image(val image:String, val thumbnail:String, val size:(Int, Int), val ima
}*/
def cloneImage:Image = {
- return new Image(imagePath,thumbnailPath,imageSize,hashes.cloneHashes)
+ new Image(imagePath,thumbnailPath,imageSize,hashes.cloneHashes)
}
override def toString:String = {
diff --git a/src/main/scala/com/sothr/imagetools/image/ImageFilter.scala b/src/main/scala/com/sothr/imagetools/image/ImageFilter.scala
index bfab988..f02196e 100644
--- a/src/main/scala/com/sothr/imagetools/image/ImageFilter.scala
+++ b/src/main/scala/com/sothr/imagetools/image/ImageFilter.scala
@@ -1,9 +1,14 @@
package com.sothr.imagetools.image
import java.io.{File, FilenameFilter}
+
import scala.collection.immutable.HashSet
/**
+ * Filter for file names
+ *
+ * Used to detect image files based on extension
+ *
* Created by drew on 1/26/14.
*/
class ImageFilter extends FilenameFilter {
diff --git a/src/main/scala/com/sothr/imagetools/image/ImageService.scala b/src/main/scala/com/sothr/imagetools/image/ImageService.scala
index 1ddf2fb..9d85bdf 100644
--- a/src/main/scala/com/sothr/imagetools/image/ImageService.scala
+++ b/src/main/scala/com/sothr/imagetools/image/ImageService.scala
@@ -1,16 +1,16 @@
-package com.sothr.imagetools
+package com.sothr.imagetools.image
+import java.awt.image.{BufferedImage, ColorConvertOp, DataBufferByte}
+import java.io.{File, IOException}
+import javax.imageio.ImageIO
+
+import com.sothr.imagetools.AppConfig
+import com.sothr.imagetools.dao.ImageDAO
+import com.sothr.imagetools.hash.HashService
+import com.sothr.imagetools.util.{PropertiesService, PropertyEnum}
import grizzled.slf4j.Logging
-import java.awt.image.{DataBufferByte, BufferedImage, ColorConvertOp}
import net.coobird.thumbnailator.Thumbnails
-import java.io.File
-import com.sothr.imagetools.image.Image
-import com.sothr.imagetools.hash.HashService
-import javax.imageio.ImageIO
-import java.io.IOException
import net.sf.ehcache.Element
-import com.sothr.imagetools.util.{PropertiesEnum, PropertiesService}
-import com.sothr.imagetools.dao.ImageDAO
object ImageService extends Logging {
@@ -80,7 +80,7 @@ object ImageService extends Logging {
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(PropertiesEnum.ThumbnailDirectory.toString)}${PropertiesService.get(PropertiesEnum.ThumbnailSize.toString)}/$subPath/"
+ 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()
@@ -105,7 +105,7 @@ object ImageService extends Logging {
def getThumbnail(image:BufferedImage, md5:String):String = {
//create thumbnail
- val thumb = resize(image, PropertiesService.get(PropertiesEnum.ThumbnailSize.toString).toInt, forced=false)
+ val thumb = resize(image, PropertiesService.get(PropertyEnum.ThumbnailSize.toString).toInt, forced=false)
//calculate path
val path = calculateThumbPath(md5)
// save thumbnail to path
@@ -129,7 +129,7 @@ object ImageService extends Logging {
/**
* Quickly convert an image to grayscale
*
- * @param image
+ * @param image image to convert to greyscale
* @return
*/
def convertToGray(image:BufferedImage):BufferedImage = {
@@ -162,7 +162,7 @@ object ImageService extends Logging {
/**
* Convert a buffered image into a 2d pixel data array
*
- * @param image
+ * @param image image to convert without using RGB
* @return
*/
private def convertTo2DWithoutUsingGetRGB(image:BufferedImage):Array[Array[Int]] = {
diff --git a/src/main/scala/com/sothr/imagetools/image/SimilarImages.scala b/src/main/scala/com/sothr/imagetools/image/SimilarImages.scala
index 09878fa..697e2d4 100644
--- a/src/main/scala/com/sothr/imagetools/image/SimilarImages.scala
+++ b/src/main/scala/com/sothr/imagetools/image/SimilarImages.scala
@@ -3,6 +3,8 @@ package com.sothr.imagetools.image
import grizzled.slf4j.Logging
/**
+ * Similar Image payload class
+ *
* Created by drew on 1/26/14.
*/
class SimilarImages(val rootImage:Image, val similarImages:List[Image]) extends Logging {
@@ -28,7 +30,7 @@ class SimilarImages(val rootImage:Image, val similarImages:List[Image]) extends
override def toString:String = {
s"""RootImage: ${rootImage.imagePath}
Similar Images:
- ${getPrettySimilarImagesList}""".stripMargin
+ $getPrettySimilarImagesList""".stripMargin
}
}
diff --git a/src/main/scala/com/sothr/imagetools/ui/component/ImageTile.scala b/src/main/scala/com/sothr/imagetools/ui/component/ImageTile.scala
index c30ec66..d064106 100644
--- a/src/main/scala/com/sothr/imagetools/ui/component/ImageTile.scala
+++ b/src/main/scala/com/sothr/imagetools/ui/component/ImageTile.scala
@@ -1,9 +1,12 @@
package com.sothr.imagetools.ui.component
import javafx.scene.layout.VBox
+
import com.sothr.imagetools.image.Image
/**
+ * ImageTile class that is a special VBox
+ *
* Created by drew on 8/22/14.
*/
class ImageTile extends VBox{
diff --git a/src/main/scala/com/sothr/imagetools/ui/component/ImageTileFactory.scala b/src/main/scala/com/sothr/imagetools/ui/component/ImageTileFactory.scala
index 6eec2f1..3dab590 100644
--- a/src/main/scala/com/sothr/imagetools/ui/component/ImageTileFactory.scala
+++ b/src/main/scala/com/sothr/imagetools/ui/component/ImageTileFactory.scala
@@ -1,29 +1,43 @@
package com.sothr.imagetools.ui.component
+import java.io.FileInputStream
import javafx.event.EventHandler
-import javafx.geometry.Pos
-import javafx.scene.Node
-import javafx.scene.control.Label
-import javafx.scene.image.{ImageView, Image}
+import javafx.geometry.{Insets, Pos}
+import javafx.scene.control.{Label, Tooltip}
+import javafx.scene.image.{Image, ImageView}
import javafx.scene.input.MouseEvent
-import javafx.scene.layout.{Background, BackgroundFill, VBox}
-import javafx.scene.paint.Color
+
+import grizzled.slf4j.Logging
+import resource._
/**
* Created by drew on 8/6/14.
*
* Creates pre-generated image tiles that can be rendered to a scene
*/
-object ImageTileFactory {
+object ImageTileFactory extends Logging {
def get(image:com.sothr.imagetools.image.Image):ImageTile = {
val imageTile = new ImageTile()
imageTile.setImageData(image)
- imageTile.setPrefSize(192.0d,192.0d)
+ //set tile size
+ imageTile.setPrefSize(160.0d,160.0d)
+ imageTile.setMinSize(160.0d,160.0d)
+ imageTile.setMaxSize(160.0d,160.0d)
+ //set padding
+ imageTile.setPadding(new Insets(2,2,2,2))
+ //imageTile.setSpacing(5.0d)
imageTile.setAlignment(Pos.TOP_CENTER)
imageTile.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler[MouseEvent] {
override def handle(event: MouseEvent): Unit = {
- if (event.isSecondaryButtonDown()) {
+ if (event.isPrimaryButtonDown) {
+ //double click
+ if (event.getClickCount == 2) {
+
+ } else {
+
+ }
+ } else if (event.isSecondaryButtonDown) {
//right click context menu
}
}
@@ -31,16 +45,30 @@ object ImageTileFactory {
// Image
val genImageView = new ImageView()
- val thumbnail = new Image(image.getThumbnailPath)
- genImageView.setImage(thumbnail)
- genImageView.setFitWidth(128.0)
+ debug(s"Getting thumbnail from: ${image.getThumbnailPath}")
+ managed(new FileInputStream(image.getThumbnailPath)) acquireAndGet {
+ thumbSource =>
+ val thumbnail = new Image(thumbSource)
+ genImageView.setImage(thumbnail)
+ if (thumbnail.getHeight > thumbnail.getWidth) {
+ genImageView.setFitHeight(128.0)
+ } else {
+ genImageView.setFitWidth(128.0)
+ }
+ }
genImageView.setPreserveRatio(true)
+
imageTile.getChildren.add(genImageView)
//Label
val imageLabel = new Label()
- imageLabel.setText(image.getName())
+ imageLabel.setText(s"${image.getHeight}x${image.getWidth}")
imageLabel.setWrapText(true)
+
+ //Tooltip
+ val tooltip = new Tooltip()
+ tooltip.setText(s"${image.getName}")
+ imageLabel.setTooltip(tooltip)
imageTile.getChildren.add(imageLabel)
imageTile
diff --git a/src/main/scala/com/sothr/imagetools/ui/controller/AppController.scala b/src/main/scala/com/sothr/imagetools/ui/controller/AppController.scala
index 1748c37..a089248 100644
--- a/src/main/scala/com/sothr/imagetools/ui/controller/AppController.scala
+++ b/src/main/scala/com/sothr/imagetools/ui/controller/AppController.scala
@@ -1,21 +1,24 @@
package com.sothr.imagetools.ui.controller
-import javafx.fxml.FXML
-import javafx.event.ActionEvent
-import javafx.stage.{DirectoryChooser, StageStyle, Stage}
-import javafx.scene.{Scene,Group}
-import javafx.scene.text.{TextAlignment, Text}
import java.io.{File, IOException}
+import java.util
import java.util.Scanner
-import com.sothr.imagetools.image.Image
+import javafx.event.ActionEvent
+import javafx.fxml.FXML
+import javafx.scene.text.{Text, TextAlignment}
+import javafx.scene.web.WebView
+import javafx.scene.{Group, Node, Scene}
+import javafx.stage.{DirectoryChooser, Stage, StageStyle}
+
+import com.sothr.imagetools.engine.{Engine, SequentialEngine}
import com.sothr.imagetools.ui.component.ImageTileFactory
-import com.sothr.imagetools.util.ResourceLoader
+import com.sothr.imagetools.util.{PropertiesService, ResourceLoader}
import grizzled.slf4j.Logging
-import javafx.scene.web.WebView
import org.markdown4j.Markdown4jProcessor
-import javafx.collections.{FXCollections}
/**
+ * Main Application controller
+ *
* Created by drew on 12/31/13.
*/
class AppController extends Logging {
@@ -29,19 +32,30 @@ class AppController extends Logging {
// Labels
@FXML var selectedDirectoryLabel: javafx.scene.control.Label = null
+ // Engine
+ val engine:Engine = new SequentialEngine()
+
+ // Current State
+ var currentDirectory:String = "."
+
@FXML def initialize() = {
- //test
- val testImage = new Image()
- testImage.setThumbnailPath("test.jpg")
- testImage.setImagePath("test.jpg")
- for (i <- 1 to 100) {
- imageTilePane.getChildren.add(ImageTileFactory.get(testImage))
- }
- val list = FXCollections.observableArrayList[String]()
- for (i <- 1 to 100) {
- list.add(s"test-item ${i}")
+ if (PropertiesService.has("lastPath")) {
+ currentDirectory = PropertiesService.get("lastPath", ".")
+ selectedDirectoryLabel.setText(PropertiesService.get("lastPath", ""))
}
- tagListView.setItems(list)
+
+ //test
+ //val testImage = new Image()
+ //testImage.setThumbnailPath("test.jpg")
+ //testImage.setImagePath("test.jpg")
+ //for (i <- 1 to 100) {
+ // imageTilePane.getChildren.add(ImageTileFactory.get(testImage))
+ //}
+ //val list = FXCollections.observableArrayList[String]()
+ //for (i <- 1 to 100) {
+ // list.add(s"test-item ${i}")
+ //}
+ //tagListView.setItems(list)
}
//region MenuItem Actions
@@ -75,7 +89,7 @@ class AppController extends Logging {
}
@FXML
- def closeAction(event:ActionEvent ) = {
+ def closeAction(event:ActionEvent) = {
debug("Closing application from the menu bar")
val stage:Stage = this.rootMenuBar.getScene.getWindow.asInstanceOf[Stage]
stage.close()
@@ -85,12 +99,39 @@ class AppController extends Logging {
def browseFolders(event:ActionEvent) = {
val chooser = new DirectoryChooser()
chooser.setTitle("ImageTools Browser")
- val defaultDirectory = new File(".")
+
+ val defaultDirectory = new File(currentDirectory)
chooser.setInitialDirectory(defaultDirectory)
val window = this.rootPane.getScene.getWindow
val selectedDirectory = chooser.showDialog(window)
info(s"Selected Directory: ${selectedDirectory.getAbsolutePath}")
selectedDirectoryLabel.setText(selectedDirectory.getAbsolutePath)
+
+ currentDirectory = selectedDirectory.getAbsolutePath
+ PropertiesService.set("lastPath",selectedDirectory.getAbsolutePath)
+ }
+
+ @FXML
+ def showAllImages(event:ActionEvent) = {
+ imageTilePane.getChildren.setAll(new util.ArrayList[Node]())
+ val images = engine.getImagesForDirectory(currentDirectory)
+ info(s"Displaying ${images.length} images")
+ for (image <- images) {
+ debug(s"Adding image ${image.toString} to app")
+ imageTilePane.getChildren.add(ImageTileFactory.get(image))
+ }
+ }
+
+ @FXML
+ def showSimilarImages(event:ActionEvent) = {
+ imageTilePane.getChildren.setAll(new util.ArrayList[Node]())
+ val similarImages = engine.getSimilarImagesForDirectory(currentDirectory)
+ info(s"Displaying ${similarImages.length} similar images")
+ for (similarImage <- similarImages) {
+ debug(s"Adding similar images ${similarImage.rootImage.toString} to app")
+ imageTilePane.getChildren.add(ImageTileFactory.get(similarImage.rootImage))
+ similarImage.similarImages.foreach( image => imageTilePane.getChildren.add(ImageTileFactory.get(image)))
+ }
}
//endregion
@@ -106,10 +147,10 @@ class AppController extends Logging {
/**
* Render HTML content to a utility dialog. No input or output, just raw rendered content through a webkit engine.
*
- * @param title
- * @param htmlBody
- * @param width
- * @param height
+ * @param title Title of the dialog
+ * @param htmlBody Body to render
+ * @param width Desired width of the dialog
+ * @param height Desired height of the dialog
*/
def showHTMLUtilityDialog(title:String, htmlBody:String, width:Double = 800.0, height:Double = 600.0) = {
val dialog:Stage = new Stage()
@@ -156,9 +197,9 @@ class AppController extends Logging {
/**
* Show a plain text utility dialog
*
- * @param message
- * @param wrapWidth
- * @param alignment
+ * @param message Message to display
+ * @param wrapWidth When to wrap
+ * @param alignment How it should be aligned
*/
def showUtilityDialog(title:String,
message:String,
@@ -188,6 +229,6 @@ class AppController extends Logging {
}
def print():String = {
- return "This method works"
+ "This method works"
}
}
diff --git a/src/main/scala/com/sothr/imagetools/util/DirectoryFilter.scala b/src/main/scala/com/sothr/imagetools/util/DirectoryFilter.scala
index 20f6941..9d191c5 100644
--- a/src/main/scala/com/sothr/imagetools/util/DirectoryFilter.scala
+++ b/src/main/scala/com/sothr/imagetools/util/DirectoryFilter.scala
@@ -3,11 +3,13 @@ package com.sothr.imagetools.util
import java.io.{File, FilenameFilter}
/**
+ * Filter directories
+ *
* Created by drew on 1/26/14.
*/
class DirectoryFilter extends FilenameFilter {
def accept(dir: File, name: String): Boolean = {
- return new File(dir, name).isDirectory();
+ new File(dir, name).isDirectory
}
}
diff --git a/src/main/scala/com/sothr/imagetools/util/PropertiesService.scala b/src/main/scala/com/sothr/imagetools/util/PropertiesService.scala
index 658724b..c55f3e7 100644
--- a/src/main/scala/com/sothr/imagetools/util/PropertiesService.scala
+++ b/src/main/scala/com/sothr/imagetools/util/PropertiesService.scala
@@ -1,10 +1,10 @@
package com.sothr.imagetools.util
+import java.io.{File, FileOutputStream, PrintStream}
+import java.util.Properties
+
import com.typesafe.config.{Config, ConfigFactory}
import grizzled.slf4j.Logging
-import java.io.{File, PrintStream, FileOutputStream}
-import java.util.Properties
-import scala.collection.JavaConversions._
/*
* Service for loading and interacting with the properties file
@@ -41,48 +41,47 @@ object PropertiesService extends Logging {
*/
def loadProperties(defaultLocation:String, userLocation:String = null) = {
info(s"Attempting to load properties from: $defaultLocation")
- defaultConf = ConfigFactory.load(defaultLocation);
+ defaultConf = ConfigFactory.load(defaultLocation)
if (userLocation != null) {
- userConf = ConfigFactory.parseFile(new File(userLocation));
+ userConf = ConfigFactory.parseFile(new File(userLocation))
} else {
userConf = ConfigFactory.empty
info("No user properties file exists to load from")
}
- version = new Version(get(PropertiesEnum.Version.toString));
+ version = new Version(get(PropertyEnum.Version.toString))
info(s"Detected Version: $version")
//load special properties
- TimingEnabled = get(PropertiesEnum.Timed.toString).toBoolean
+ TimingEnabled = get(PropertyEnum.Timed.toString).toBoolean
//ahash
- aHashPrecision = get(PropertiesEnum.AhashPrecision.toString).toInt
- aHashTolerance = get(PropertiesEnum.AhashTolerance.toString).toInt
- aHashWeight = get(PropertiesEnum.AhashWeight.toString).toFloat
- useAhash = get(PropertiesEnum.UseAhash.toString).toBoolean
+ aHashPrecision = get(PropertyEnum.AhashPrecision.toString).toInt
+ aHashTolerance = get(PropertyEnum.AhashTolerance.toString).toInt
+ aHashWeight = get(PropertyEnum.AhashWeight.toString).toFloat
+ useAhash = get(PropertyEnum.UseAhash.toString).toBoolean
//dhash
- dHashPrecision = get(PropertiesEnum.DhashPrecision.toString).toInt
- dHashTolerance = get(PropertiesEnum.DhashTolerance.toString).toInt
- dHashWeight = get(PropertiesEnum.DhashWeight.toString).toFloat
- useDhash = get(PropertiesEnum.UseDhash.toString).toBoolean
+ dHashPrecision = get(PropertyEnum.DhashPrecision.toString).toInt
+ dHashTolerance = get(PropertyEnum.DhashTolerance.toString).toInt
+ dHashWeight = get(PropertyEnum.DhashWeight.toString).toFloat
+ useDhash = get(PropertyEnum.UseDhash.toString).toBoolean
//phash
- pHashPrecision = get(PropertiesEnum.PhashPrecision.toString).toInt
- pHashTolerance = get(PropertiesEnum.PhashTolerance.toString).toInt
- pHashWeight = get(PropertiesEnum.PhashWeight.toString).toFloat
- usePhash = get(PropertiesEnum.UsePhash.toString).toBoolean
+ pHashPrecision = get(PropertyEnum.PhashPrecision.toString).toInt
+ pHashTolerance = get(PropertyEnum.PhashTolerance.toString).toInt
+ pHashWeight = get(PropertyEnum.PhashWeight.toString).toFloat
+ usePhash = get(PropertyEnum.UsePhash.toString).toBoolean
info("Loaded Special Properties")
}
private def cleanAndPrepareNewUserProperties():Properties = {
//insert special keys here
- newUserConf.setProperty(PropertiesEnum.PreviousVersion.toString, version.parsableToString())
+ newUserConf.setProperty(PropertyEnum.PreviousVersion.toString, version.parsableToString())
//remove special keys here
- newUserConf.remove(PropertiesEnum.Version.toString)
+ newUserConf.remove(PropertyEnum.Version.toString)
newUserConf
}
- private def getCleanedMergedUserConf():Config = {
-
- ConfigFactory.parseProperties(cleanAndPrepareNewUserProperties()) withFallback(userConf)
+ private def getCleanedMergedUserConf:Config = {
+ ConfigFactory.parseProperties(cleanAndPrepareNewUserProperties()) withFallback userConf
}
def saveConf(location:String) = {
@@ -95,6 +94,16 @@ object PropertiesService extends Logging {
out.close()
}
+ def has(key:String):Boolean = {
+ var result = false
+ if (newUserConf.containsKey(key)
+ || userConf.hasPath(key)
+ || defaultConf.hasPath(key)) {
+ result = true
+ }
+ result
+ }
+
def get(key:String, defaultValue:String=null):String = {
var result:String = defaultValue
//check the latest properties
@@ -109,7 +118,7 @@ object PropertiesService extends Logging {
else if (defaultConf.hasPath(key)) {
result = defaultConf.getString(key)
}
- return result
+ result
}
def set(key:String, value:String) = {
diff --git a/src/main/scala/com/sothr/imagetools/util/PropertiesEnum.scala b/src/main/scala/com/sothr/imagetools/util/PropertyEnum.scala
similarity index 81%
rename from src/main/scala/com/sothr/imagetools/util/PropertiesEnum.scala
rename to src/main/scala/com/sothr/imagetools/util/PropertyEnum.scala
index cf94fe0..ceff64c 100644
--- a/src/main/scala/com/sothr/imagetools/util/PropertiesEnum.scala
+++ b/src/main/scala/com/sothr/imagetools/util/PropertyEnum.scala
@@ -1,13 +1,13 @@
package com.sothr.imagetools.util
-object PropertiesEnum extends Enumeration {
+object PropertyEnum extends Enumeration {
type PropertiesEnum = Value
val Version = Value("app.version.current")
val PreviousVersion = Value("app.version.previous")
//default app settings
val Timed = Value("app.timed")
//default engine concurrency settings
- val ConcurrentSimiliartyLimit = Value("app.engine.concurrent.similarity.limit")
+ val ConcurrentSimilarityLimit = Value("app.engine.concurrent.similarity.limit")
val ConcurrentProcessingLimit = Value("app.engine.concurrent.processing.limit")
//default image settings
val ImageDifferenceThreshold = Value("app.image.differenceThreshold")
@@ -15,15 +15,15 @@ object PropertiesEnum extends Enumeration {
val UseAhash = Value("app.image.ahash.use")
val AhashWeight = Value("app.image.ahash.weight")
val AhashPrecision = Value("app.image.ahash.precision")
- val AhashTolerance = Value("app.image.ahash.tolerence")
+ val AhashTolerance = Value("app.image.ahash.tolerance")
val UseDhash = Value("app.image.dhash.use")
val DhashWeight = Value("app.image.dhash.weight")
val DhashPrecision = Value("app.image.dhash.precision")
- val DhashTolerance = Value("app.image.dhash.tolerence")
+ val DhashTolerance = Value("app.image.dhash.tolerance")
val UsePhash = Value("app.image.phash.use")
val PhashWeight = Value("app.image.phash.weight")
val PhashPrecision = Value("app.image.phash.precision")
- val PhashTolerance = Value("app.image.phash.tolerence")
+ val PhashTolerance = Value("app.image.phash.tolerance")
//Default Thumbnail Settings
val ThumbnailDirectory = Value("app.thumbnail.directory")
val ThumbnailSize = Value("app.thumbnail.size")
diff --git a/src/main/scala/com/sothr/imagetools/util/Version.scala b/src/main/scala/com/sothr/imagetools/util/Version.scala
index e750077..7e5ccf6 100644
--- a/src/main/scala/com/sothr/imagetools/util/Version.scala
+++ b/src/main/scala/com/sothr/imagetools/util/Version.scala
@@ -1,16 +1,17 @@
package com.sothr.imagetools.util
import grizzled.slf4j.Logging
-import java.lang.NumberFormatException
/**
+ * Class to handle version detection and evaluation
+ *
* Created by drew on 1/6/14.
*/
class Version(val versionString:String) extends Logging{
//parse version into parts
//typical version string i.e. 0.1.0-DEV-27-060aec7
val (major,minor,patch,buildTag,buildNumber,buildHash) = {
- var version:Tuple6[Int,Int,Int,String,Int,String] = (0,0,0,"DEV",0,"asdfzxcv")
+ var version:(Int, Int, Int, String, Int, String) = (0,0,0,"DEV",0,"asdfzxcv")
try {
val splitVersion = versionString.split("""\.""")
val splitType = splitVersion(splitVersion.length-1).split("""-""")
@@ -33,30 +34,39 @@ class Version(val versionString:String) extends Logging{
* 4 = this.buildTag != that.buildTag
*/
def compare(that:Version):Integer = {
- if (this.hashCode == that.hashCode) return 0
- if (this.major > that.major) {
- return 1
+ //Identical Versions
+ if (this.hashCode == that.hashCode) {
+ 0
+ // This is at least a major version ahead
+ } else if (this.major > that.major) {
+ 1
+ // This is at least a major version behind
} else if (this.major < that.major){
- return -1
- //major is the same
+ -1
+ // major is the same
} else {
+ // This is at least a minor version ahead
if (this.minor > that.minor) {
- return 2
+ 2
+ // This is at least a minor version behind
} else if (this.minor < that.minor) {
- return -2
- //major.minor are the same
+ -2
+ // major.minor are the same
} else {
+ // This is at least a patch version ahead
if (this.patch > that.patch) {
- return 3
+ 3
+ // This is at least a patch version version
} else if (this.patch < that.patch) {
- return -3
+ -3
//major.minor.patch are all the same
} else {
+ // This is a different build
if (this.buildTag != that.buildTag) {
- return 4
+ 4
}
- //should be caught by the first if, but incase not
- return 0
+ //should be caught by the first if, but in case not
+ 0
}
}
}
@@ -66,17 +76,17 @@ class Version(val versionString:String) extends Logging{
s"$major.$minor.$patch-$buildTag-$buildNumber-$buildHash"
}
- override def toString():String = {
+ override def toString:String = {
s"$major.$minor.$patch-$buildTag build:$buildNumber code:$buildHash"
}
override def hashCode(): Int = {
- val prime:Int = 37;
+ val prime:Int = 37
val result:Int = 255
var hash:Int = major
hash += minor
hash += patch
hash += buildTag.hashCode
- return prime * result + hash
+ prime * result + hash
}
}
diff --git a/src/test/resources/application.conf b/src/test/resources/application.conf
index 9242764..8bc8020 100644
--- a/src/test/resources/application.conf
+++ b/src/test/resources/application.conf
@@ -29,20 +29,20 @@ app {
use = true
weight = 0.70
precision = 8
- tolerence = 8
+ tolerance = 8
}
dhash {
use = true
weight = 0.85
precision = 8
- tolerence = 8
+ tolerance = 8
}
phash {
//set to false if hashing images is taking too long
use = true
weight = 1.0
precision = 32
- tolerence = 8
+ tolerance = 8
}
}
//Default Thumbnail Settings
diff --git a/src/test/scala/com/sothr/imagetools/BaseTest.scala b/src/test/scala/com/sothr/imagetools/BaseTest.scala
index 67aa43b..c2ce6f8 100644
--- a/src/test/scala/com/sothr/imagetools/BaseTest.scala
+++ b/src/test/scala/com/sothr/imagetools/BaseTest.scala
@@ -1,8 +1,8 @@
package com.sothr.imagetools
-import grizzled.slf4j.Logging
import com.sothr.imagetools.util.Timing
-import org.scalatest.{FunSuite,Matchers,OptionValues,Inside,Inspectors,BeforeAndAfter}
+import grizzled.slf4j.Logging
+import org.scalatest.{BeforeAndAfter, FunSuite, Inside, Inspectors, Matchers, OptionValues}
abstract class BaseTest extends FunSuite with Matchers with OptionValues with Inside with Inspectors with BeforeAndAfter with Logging with Timing {
diff --git a/src/test/scala/com/sothr/imagetools/EngineTest.scala b/src/test/scala/com/sothr/imagetools/EngineTest.scala
index 5051927..c4586f1 100644
--- a/src/test/scala/com/sothr/imagetools/EngineTest.scala
+++ b/src/test/scala/com/sothr/imagetools/EngineTest.scala
@@ -1,6 +1,10 @@
package com.sothr.imagetools
+import com.sothr.imagetools.engine.{ConcurrentEngine, Engine, SequentialEngine}
+
/**
+ * Basic Test of the engines
+ *
* Created by drew on 1/26/14.
*/
class EngineTest extends BaseTest{
diff --git a/src/test/scala/com/sothr/imagetools/ScalaAppTest.scala b/src/test/scala/com/sothr/imagetools/ScalaAppTest.scala
index b534805..953f0c1 100644
--- a/src/test/scala/com/sothr/imagetools/ScalaAppTest.scala
+++ b/src/test/scala/com/sothr/imagetools/ScalaAppTest.scala
@@ -3,7 +3,7 @@ package com.sothr.imagetools
class ScalaAppTest extends BaseTest {
test("I Do Nothing Just Make Sure The Framework Works") {
- assert(true);
+ assert(true)
}
}
diff --git a/src/test/scala/com/sothr/imagetools/hash/HashServiceTest.scala b/src/test/scala/com/sothr/imagetools/hash/HashServiceTest.scala
index 9aad23e..f605be8 100644
--- a/src/test/scala/com/sothr/imagetools/hash/HashServiceTest.scala
+++ b/src/test/scala/com/sothr/imagetools/hash/HashServiceTest.scala
@@ -1,13 +1,17 @@
package com.sothr.imagetools.hash
-import com.sothr.imagetools.{AppConfig, BaseTest, TestParams}
-import javax.imageio.ImageIO
import java.io.File
+import javax.imageio.ImageIO
+
import com.sothr.imagetools.dto.ImageHashDTO
-import net.sf.ehcache.{Cache, Element}
+import com.sothr.imagetools.{AppConfig, BaseTest, TestParams}
+import net.sf.ehcache.Element
+
import scala.collection.mutable
/**
+ * Test the Hash service and make sure it is consistent
+ *
* Created by dev on 1/23/14.
*/
class HashServiceTest extends BaseTest {
@@ -60,7 +64,7 @@ class HashServiceTest extends BaseTest {
Array(64,63,62,61,60,59,58,57))
val hash = DHash.getHash(testData)
debug(s"Hash of test array: $hash")
- assert(hash == (Long.MaxValue))
+ assert(hash == Long.MaxValue)
}
test("Calculate DHash Large Sample Image 1") {
@@ -389,21 +393,21 @@ class HashServiceTest extends BaseTest {
test("Calculate ImageHash Large Sample Image 1") {
debug("Starting 'Calculate ImageHash Large Sample Image 1' test")
val hash = HashService.getImageHashes(TestParams.LargeSampleImage1)
- debug(s"Testing that ${hash.hashCode} = -812844858")
+ debug(s"Testing that ${hash.hashCode()} = -812844858")
assert(hash.hashCode == -812844858)
}
test("Calculate ImageHash Medium Sample Image 1") {
debug("Starting 'Calculate ImageHash Medium Sample Image 1' test")
val hash = HashService.getImageHashes(TestParams.MediumSampleImage1)
- debug(s"Testing that ${hash.hashCode} = -812836666")
+ debug(s"Testing that ${hash.hashCode()} = -812836666")
assert(hash.hashCode == -812836666)
}
test("Calculate ImageHash Small Sample Image 1") {
debug("Starting 'Calculate ImageHash Small Sample Image 1' test")
val hash = HashService.getImageHashes(TestParams.SmallSampleImage1)
- debug(s"Testing that ${hash.hashCode} = -812840762")
+ debug(s"Testing that ${hash.hashCode()} = -812840762")
assert(hash.hashCode == -812840762)
}
diff --git a/src/test/scala/com/sothr/imagetools/image/ImageFilterTest.scala b/src/test/scala/com/sothr/imagetools/image/ImageFilterTest.scala
index f8857a1..83b10d1 100644
--- a/src/test/scala/com/sothr/imagetools/image/ImageFilterTest.scala
+++ b/src/test/scala/com/sothr/imagetools/image/ImageFilterTest.scala
@@ -1,9 +1,12 @@
package com.sothr.imagetools.image
-import com.sothr.imagetools.BaseTest
import java.io.File
+import com.sothr.imagetools.BaseTest
+
/**
+ * Test to make sure that the image filters work
+ *
* Created by drew on 1/26/14.
*/
class ImageFilterTest extends BaseTest{