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.

147 lines
4.1 KiB

8 years ago
  1. // Copyright 2015 Drew Short <drew@sothr.com>.
  2. //
  3. // Licensed under the MIT license<LICENSE-MIT or http://opensource.org/licenses/MIT>.
  4. // This file may not be copied, modified, or distributed except according to those terms.
  5. extern crate docopt;
  6. extern crate pihash;
  7. extern crate rustc_serialize;
  8. #[macro_use]
  9. extern crate serde_derive;
  10. use std::path::Path;
  11. use docopt::Docopt;
  12. // Getting the version information from cargo during compile time
  13. const VERSION: &'static str = env!("CARGO_PKG_VERSION");
  14. // The usage description
  15. const USAGE: &'static str = "
  16. Perceptual Image Hashing (pihash)
  17. Calculate the perceptual hash values for an input or compare the
  18. input file to a set of other images and return a list of the similar
  19. images.
  20. Usage:
  21. pihash [options] <path> [<comparison>...]
  22. pihash (--help | --version)
  23. Options:
  24. -h, --help Show this screen.
  25. -V, --version Print version.
  26. -a, --ahash Include an ahash calculation.
  27. -d, --dhash Include an dhash calculation.
  28. -p, --phash Include an phash calculation.
  29. -n, --nocache Disable caching behavior.
  30. ";
  31. #[derive(Debug, Deserialize)]
  32. struct Args {
  33. flag_version: bool,
  34. flag_ahash: bool,
  35. flag_dhash: bool,
  36. flag_phash: bool,
  37. arg_path: String,
  38. arg_comparison: Vec<String>,
  39. flag_nocache: bool,
  40. }
  41. fn main() {
  42. let args: Args = Docopt::new(USAGE)
  43. .and_then(|d| d.deserialize())
  44. .unwrap_or_else(|e| e.exit());
  45. // Print version information and exit
  46. if args.flag_version {
  47. println!("Perceptual Image Hashing: v{}", VERSION);
  48. std::process::exit(0);
  49. }
  50. let cache = if args.flag_nocache {
  51. None
  52. } else {
  53. Some(pihash::cache::DEFAULT_CACHE_DIR)
  54. };
  55. // Init the hashing library
  56. let lib = pihash::PIHash::new(cache);
  57. // println!("{:?}", args);
  58. if args.arg_comparison.len() > 0 {
  59. let base_image_path = Path::new(&args.arg_path);
  60. let base_hash = get_requested_perceptual_hashes(&lib, &base_image_path, &args);
  61. let mut comparison_hashes: Vec<pihash::hash::PerceptualHashes> = Vec::new();
  62. for index in 0..args.arg_comparison.len() {
  63. comparison_hashes.push(get_requested_perceptual_hashes(
  64. &lib,
  65. &Path::new(&args.arg_comparison[index]),
  66. &args,
  67. ));
  68. }
  69. let mut similar_images: Vec<String> = Vec::new();
  70. for comparison_hash in comparison_hashes {
  71. if base_hash.similar(&comparison_hash) {
  72. similar_images.push(String::from(&comparison_hash.orig_path));
  73. }
  74. }
  75. println!("Base Image:");
  76. println!("{}", base_image_path.to_str().unwrap());
  77. println!("Similar Images:");
  78. for similar_image in similar_images {
  79. println!("{}", similar_image);
  80. }
  81. } else {
  82. let image_path = Path::new(&args.arg_path);
  83. let hashes = get_requested_perceptual_hashes(&lib, &image_path, &args);
  84. let hash_result = format!(
  85. r#"
  86. file: {}
  87. ahash: {}
  88. dhash: {}
  89. phash: {}
  90. "#,
  91. hashes.orig_path, hashes.ahash, hashes.dhash, hashes.phash
  92. );
  93. println!("{}", hash_result);
  94. }
  95. }
  96. fn flags_get_all_perceptual_hashes(args: &Args) -> bool {
  97. (args.flag_ahash && args.flag_dhash && args.flag_phash)
  98. || (!args.flag_ahash && !args.flag_dhash && !args.flag_phash)
  99. }
  100. fn get_requested_perceptual_hashes(
  101. lib: &pihash::PIHash,
  102. image_path: &Path,
  103. args: &Args,
  104. ) -> pihash::hash::PerceptualHashes {
  105. let ahash = if args.flag_ahash || flags_get_all_perceptual_hashes(&args) {
  106. lib.get_ahash(&image_path)
  107. } else {
  108. 0u64
  109. };
  110. let dhash = if args.flag_dhash || flags_get_all_perceptual_hashes(&args) {
  111. lib.get_dhash(&image_path)
  112. } else {
  113. 0u64
  114. };
  115. let phash = if args.flag_phash || flags_get_all_perceptual_hashes(&args) {
  116. lib.get_phash(&image_path)
  117. } else {
  118. 0u64
  119. };
  120. pihash::hash::PerceptualHashes {
  121. orig_path: String::from(image_path.to_str().unwrap()),
  122. ahash,
  123. dhash,
  124. phash,
  125. }
  126. }