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.

183 lines
6.0 KiB

  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 image;
  6. extern crate sha1;
  7. use self::image::ImageBuffer;
  8. use self::sha1::Sha1;
  9. use std::path::Path;
  10. use std::fs::{File, create_dir_all, remove_dir_all};
  11. use std::io::{Read, Error, Write};
  12. use std::option::Option;
  13. use std::result::Result;
  14. const CACHE_DIR: &'static str = "./.hash_cache";
  15. const CACHE_FILE_EXT: &'static str = "png";
  16. // Creates the required directories
  17. pub fn prep_cache() -> Result<(), Error> {
  18. create_dir_all(CACHE_DIR)
  19. }
  20. pub fn clear_cache() -> Result<(), Error> {
  21. remove_dir_all(CACHE_DIR)
  22. }
  23. /**
  24. * Get the hash of the desired file and return it as a hex string
  25. */
  26. fn get_file_hash(path: &Path) -> Result<String, Error> {
  27. let mut source = try!(File::open(&path));
  28. let mut buf: Vec<u8> = Vec::new();
  29. try!(source.read_to_end(&mut buf));
  30. let mut sha1 = Sha1::new();
  31. sha1.update(&buf);
  32. // Return the hex result of the hash
  33. Ok(sha1.hexdigest())
  34. }
  35. /**
  36. * Put an image buffer in the cache
  37. */
  38. pub fn put_image_in_cache(path: &Path, size: u32, image: &ImageBuffer<image::Luma<u8>, Vec<u8>>) {
  39. let hash = get_file_hash(&path);
  40. match hash {
  41. Ok(sha1) => {
  42. let cache_path_str = format!("{}/{}x{}_{}.{}",
  43. CACHE_DIR,
  44. size,
  45. size,
  46. sha1,
  47. CACHE_FILE_EXT);
  48. let cached_path = Path::new(&cache_path_str);
  49. // Save the file into the cache
  50. match image.save(cached_path) {
  51. Ok(_) => {}
  52. Err(e) => println!("Error: {}", e),
  53. }
  54. }
  55. Err(e) => println!("Error: {}", e),
  56. }
  57. }
  58. /**
  59. * Expects a slice of slices that represents lines in the file
  60. */
  61. pub fn put_matrix_in_cache(path: &Path,
  62. size: u32,
  63. extension: &str,
  64. file_contents: &Vec<Vec<f64>>) {
  65. let hash = get_file_hash(&path);
  66. match hash {
  67. Ok(sha1) => {
  68. let cache_path_str = format!("{}/{}x{}_{}.{}", CACHE_DIR, size, size, sha1, extension);
  69. let cached_path = Path::new(&cache_path_str);
  70. // Save the file into the cache
  71. match File::create(&cached_path) {
  72. Ok(mut file) => {
  73. for row in file_contents {
  74. let mut row_str = row.iter().fold(String::new(),
  75. |acc, &item| acc + &format!("{},", item));
  76. // remove the last comma
  77. let desire_len = row_str.len() - 1;
  78. row_str.truncate(desire_len);
  79. row_str.push_str("\n");
  80. file.write(&row_str.into_bytes());
  81. }
  82. file.flush();
  83. }
  84. Err(_) => {}
  85. }
  86. }
  87. Err(e) => println!("Error: {}", e),
  88. }
  89. }
  90. /**
  91. * Get an image buffer out of the cache
  92. */
  93. pub fn get_image_from_cache(path: &Path,
  94. size: u32)
  95. -> Option<ImageBuffer<image::Luma<u8>, Vec<u8>>> {
  96. let hash = get_file_hash(&path);
  97. match hash {
  98. Ok(sha1) => {
  99. // Check if the file exists in the cache
  100. let cache_path_str = format!("{}/{}x{}_{}.{}",
  101. CACHE_DIR,
  102. size,
  103. size,
  104. sha1,
  105. CACHE_FILE_EXT);
  106. let cached_path = Path::new(&cache_path_str);
  107. // Try to open, if it does, then we can read the image in
  108. match File::open(&cached_path) {
  109. Ok(_) => {
  110. let image = image::open(&cached_path).unwrap();
  111. Some(image.to_luma())
  112. }
  113. // Don't really care here, it just means an existing cached
  114. // file doesn't exist, or can't be read.
  115. Err(_) => None,
  116. }
  117. }
  118. Err(e) => {
  119. println!("Error: {}", e);
  120. None
  121. }
  122. }
  123. }
  124. /**
  125. * Get a matrix out of the cache
  126. */
  127. pub fn get_matrix_from_cache(path: &Path, size: u32, extension: &str) -> Option<Vec<Vec<f64>>> {
  128. let hash = get_file_hash(&path);
  129. match hash {
  130. Ok(sha1) => {
  131. // Check if the file exists in the cache
  132. let cache_path_str = format!("{}/{}x{}_{}.{}", CACHE_DIR, size, size, sha1, extension);
  133. let cached_path = Path::new(&cache_path_str);
  134. // Try to open, if it does, then we can read the image in
  135. match File::open(&cached_path) {
  136. Ok(mut file) => {
  137. let mut matrix: Vec<Vec<f64>> = Vec::new();
  138. let mut matrix_data: Vec<u8> = Vec::new();
  139. file.read_to_end(&mut matrix_data);
  140. let matrix_data_str = String::from_utf8(matrix_data);
  141. // convert the matrix
  142. Some(matrix)
  143. }
  144. // Don't really care here, it just means an existing cached
  145. // file doesn't exist, or can't be read.
  146. Err(_) => None,
  147. }
  148. }
  149. Err(e) => {
  150. println!("Error: {}", e);
  151. None
  152. }
  153. }
  154. }
  155. #[test]
  156. fn test_get_file_hash() {
  157. let target = "test_images/sample_01_large.jpg";
  158. let target_path = Path::new(target);
  159. let hash = get_file_hash(&target_path);
  160. match hash {
  161. Ok(v) => {
  162. println!("Hash: {}", v);
  163. assert!(v == "4beb6f2d852b75a313863916a1803ebad13a3196");
  164. }
  165. Err(e) => {
  166. println!("Error: {:?}", e);
  167. assert!(false);
  168. }
  169. }
  170. }