@@ -310,14 +310,6 @@ dependencies = [ | |||
"strum_macros 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
name = "enum_primitive" | |||
version = "0.1.1" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
name = "error-chain" | |||
version = "0.11.0" | |||
@@ -331,7 +323,7 @@ name = "errors" | |||
version = "0.1.0" | |||
dependencies = [ | |||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"image 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"tera 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
@@ -432,7 +424,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
[[package]] | |||
name = "gif" | |||
version = "0.9.2" | |||
version = "0.10.0" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
@@ -540,17 +532,18 @@ dependencies = [ | |||
[[package]] | |||
name = "image" | |||
version = "0.18.0" | |||
version = "0.19.0" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"gif 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"png 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
@@ -559,7 +552,7 @@ name = "imageproc" | |||
version = "0.1.0" | |||
dependencies = [ | |||
"errors 0.1.0", | |||
"image 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", | |||
@@ -570,7 +563,7 @@ dependencies = [ | |||
[[package]] | |||
name = "inflate" | |||
version = "0.3.4" | |||
version = "0.4.2" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||
@@ -892,6 +885,17 @@ dependencies = [ | |||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
name = "num-derive" | |||
version = "0.2.2" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
name = "num-integer" | |||
version = "0.1.39" | |||
@@ -918,14 +922,6 @@ dependencies = [ | |||
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
name = "num-traits" | |||
version = "0.1.43" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
[[package]] | |||
name = "num-traits" | |||
version = "0.2.5" | |||
@@ -1066,12 +1062,12 @@ dependencies = [ | |||
[[package]] | |||
name = "png" | |||
version = "0.11.0" | |||
version = "0.12.0" | |||
source = "registry+https://github.com/rust-lang/crates.io-index" | |||
dependencies = [ | |||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"inflate 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"inflate 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", | |||
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", | |||
] | |||
@@ -1945,7 +1941,6 @@ dependencies = [ | |||
"checksum duct 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "166298c17c5b4fe5997b962c2f22e887c7c5adc44308eb9103ce5b66af45a423" | |||
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" | |||
"checksum elasticlunr-rs 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4837d77a1e157489a3933b743fd774ae75074e0e390b2b7f071530048a0d87ee" | |||
"checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" | |||
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" | |||
"checksum filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "714653f3e34871534de23771ac7b26e999651a0a228f47beb324dfdf1dd4b10f" | |||
"checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" | |||
@@ -1958,7 +1953,7 @@ dependencies = [ | |||
"checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" | |||
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" | |||
"checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05" | |||
"checksum gif 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e41945ba23db3bf51b24756d73d81acb4f28d85c3dccc32c6fae904438c25f" | |||
"checksum gif 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff3414b424657317e708489d2857d9575f4403698428b040b609b9d1c1a84a2c" | |||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" | |||
"checksum globset 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "142754da2c9b3722affd909f9e27f2a6700a7a303f362971e0a74c652005a43d" | |||
"checksum html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b04478cf718862650a0bf66acaf8f2f8c906fbc703f35c916c1f4211b069a364" | |||
@@ -1966,8 +1961,8 @@ dependencies = [ | |||
"checksum humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e" | |||
"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" | |||
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" | |||
"checksum image 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "545f000e8aa4e569e93f49c446987133452e0091c2494ac3efd3606aa3d309f2" | |||
"checksum inflate 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f5f9f47468e9a76a6452271efadc88fe865a82be91fe75e6c0c57b87ccea59d4" | |||
"checksum image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebdff791af04e30089bde8ad2a632b86af433b40c04db8d70ad4b21487db7a6a" | |||
"checksum inflate 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec18d981200fd14e65ee8e35fb60ed1ce55227a02407303f3a72517c6146dcc" | |||
"checksum inotify 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887fcc180136e77a85e6a6128579a719027b1bab9b1c38ea4444244fe262c20c" | |||
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" | |||
"checksum iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8e17268922834707e1c29e8badbf9c712c9c43378e1b6a3388946baff10be2" | |||
@@ -2004,10 +1999,10 @@ dependencies = [ | |||
"checksum nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79" | |||
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" | |||
"checksum notify 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5c3812da3098f210a0bb440f9c008471a031aa4c1de07a264fdd75456c95a4eb" | |||
"checksum num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2c31b75c36a993d30c7a13d70513cb93f02acafdd5b7ba250f9b0e18615de7" | |||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" | |||
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" | |||
"checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" | |||
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" | |||
"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" | |||
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" | |||
"checksum onig 3.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f5eeb268a4620c74ea5768c6d2ccd492d60a47a8754666b91a46bfc35cd4d1ba" | |||
@@ -2023,7 +2018,7 @@ dependencies = [ | |||
"checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f" | |||
"checksum plist 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c61ac2afed2856590ae79d6f358a24b85ece246d2aa134741a66d589519b7503" | |||
"checksum plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a6a0dc3910bc8db877ffed8e457763b317cf880df4ae19109b9f77d277cf6e0" | |||
"checksum png 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f0b0cabbbd20c2d7f06dbf015e06aad59b6ca3d9ed14848783e98af9aaf19925" | |||
"checksum png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f54b9600d584d3b8a739e1662a595fab051329eff43f20e7d8cc22872962145b" | |||
"checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" | |||
"checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" | |||
"checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6" | |||
@@ -267,9 +267,9 @@ impl ser::Serialize for Page { | |||
state.serialize_field("next", &self.next)?; | |||
state.serialize_field("toc", &self.toc)?; | |||
state.serialize_field("draft", &self.is_draft())?; | |||
let (assets, assets_imgs) = self.serialize_assets(); | |||
let (assets, images) = self.serialize_assets(); | |||
state.serialize_field("assets", &assets)?; | |||
state.serialize_field("assets_imgs", &assets_imgs)?; | |||
state.serialize_field("images", &images)?; | |||
state.end() | |||
} | |||
} | |||
@@ -7,4 +7,4 @@ authors = ["Vincent Prouillet <prouillet.vincent@gmail.com>"] | |||
error-chain = "0.11" | |||
tera = "0.11" | |||
toml = "0.4" | |||
image = "0.18.0" | |||
image = "0.19.0" |
@@ -7,7 +7,7 @@ authors = ["Vojtěch Král <vojtech@kral.hk>"] | |||
lazy_static = "1" | |||
regex = "0.2" | |||
tera = "0.11.0" | |||
image = "0.18.0" | |||
image = "0.19.0" | |||
rayon = "0.9" | |||
twox-hash = "1.1" | |||
@@ -52,8 +52,8 @@ impl ResizeOp { | |||
// Validate args: | |||
match op { | |||
"fitwidth" => if width.is_none() { return Err(format!("op=fitwidth requires a `width` argument").into()) }, | |||
"fitheight" => if height.is_none() { return Err(format!("op=fitwidth requires a `height` argument").into()) }, | |||
"fit_width" => if width.is_none() { return Err(format!("op=\"fit_width\" requires a `width` argument").into()) }, | |||
"fit_height" => if height.is_none() { return Err(format!("op=\"fit_height\" requires a `height` argument").into()) }, | |||
"scale" | "fit" | "fill" => if width.is_none() || height.is_none() { | |||
return Err(format!("op={} requires a `width` and `height` argument", op).into()) | |||
}, | |||
@@ -62,8 +62,8 @@ impl ResizeOp { | |||
Ok(match op { | |||
"scale" => Scale(width.unwrap(), height.unwrap()), | |||
"fitwidth" => FitWidth(width.unwrap()), | |||
"fitheight" => FitHeight(height.unwrap()), | |||
"fit_width" => FitWidth(width.unwrap()), | |||
"fit_height" => FitHeight(height.unwrap()), | |||
"fit" => Fit(width.unwrap(), height.unwrap()), | |||
"fill" => Fill(width.unwrap(), height.unwrap()), | |||
_ => unreachable!(), | |||
@@ -123,6 +123,7 @@ pub struct ImageOp { | |||
source: String, | |||
op: ResizeOp, | |||
quality: u8, | |||
/// Hash of the above parameters | |||
hash: u64, | |||
collision: Option<u32>, | |||
} | |||
@@ -143,7 +144,7 @@ impl ImageOp { | |||
Ok(Self::new(source, op, quality)) | |||
} | |||
fn num_colli(&self) -> u32 { self.collision.unwrap_or(0) } | |||
fn num_collisions(&self) -> u32 { self.collision.unwrap_or(0) } | |||
fn perform(&self, content_path: &Path, target_path: &Path) -> Result<()> { | |||
use ResizeOp::*; | |||
@@ -165,24 +166,30 @@ impl ImageOp { | |||
FitHeight(h) => img.resize(u32::max_value(), h, RESIZE_FILTER), | |||
Fit(w, h) => img.resize(w, h, RESIZE_FILTER), | |||
Fill(w, h) => { | |||
let fw = img_w as f32 / w as f32; | |||
let fh = img_h as f32 / h as f32; | |||
let factor_w = img_w as f32 / w as f32; | |||
let factor_h = img_h as f32 / h as f32; | |||
if (fw - fh).abs() <= RATIO_EPSILLION { | |||
// The aspect is similar enough that there's not much point in cropping | |||
if (factor_w - factor_h).abs() <= RATIO_EPSILLION { | |||
// If the horizontal and vertical factor is very similar, that means the aspect is similar enough | |||
// that there's not much point in cropping, so just perform a simple scale in this case. | |||
img.resize_exact(w, h, RESIZE_FILTER) | |||
} else { | |||
// We perform the fill such that a crop is performed first and then resize_exact can be used, | |||
// which should be cheaper than resizing and then cropping (smaller number of pixels to resize). | |||
let (crop_w, crop_h) = match fw < fh { | |||
true => (img_w, (fw * h as f32).round() as u32), | |||
false => ((fh * w as f32).round() as u32, img_h), | |||
let (crop_w, crop_h) = if factor_w < factor_h { | |||
(img_w, (factor_w * h as f32).round() as u32) | |||
} else { | |||
((factor_h * w as f32).round() as u32, img_h) | |||
}; | |||
let (off_w, off_h) = match fw < fh { | |||
true => (0, (img_h - crop_h) / 2), | |||
false => ((img_w - crop_w) / 2, 0), | |||
let (offset_w, offset_h) = if factor_w < factor_h { | |||
(0, (img_h - crop_h) / 2) | |||
} else { | |||
((img_w - crop_w) / 2, 0) | |||
}; | |||
img.crop(off_w, off_h, crop_w, crop_h).resize_exact(w, h, RESIZE_FILTER) | |||
img.crop(offset_w, offset_h, crop_w, crop_h).resize_exact(w, h, RESIZE_FILTER) | |||
} | |||
}, | |||
}; | |||
@@ -204,9 +211,12 @@ pub struct Processor { | |||
content_path: PathBuf, | |||
resized_path: PathBuf, | |||
resized_url: String, | |||
/// A map of a ImageOps by their stored hash. | |||
/// Note that this cannot be a HashSet, because hashest handles collisions and we don't want that, | |||
/// we need to be aware of and handle collisions ourselves. | |||
img_ops: HashMap<u64, ImageOp>, | |||
// Hash collisions go here: | |||
img_ops_colls: Vec<ImageOp>, | |||
/// Hash collisions go here: | |||
img_ops_collisions: Vec<ImageOp>, | |||
} | |||
impl Processor { | |||
@@ -216,14 +226,15 @@ impl Processor { | |||
resized_path: static_path.join(RESIZED_SUBDIR), | |||
resized_url: Self::resized_url(base_url), | |||
img_ops: HashMap::new(), | |||
img_ops_colls: Vec::new(), | |||
img_ops_collisions: Vec::new(), | |||
} | |||
} | |||
fn resized_url(base_url: &str) -> String { | |||
match base_url.ends_with('/') { | |||
true => format!("{}{}", base_url, RESIZED_SUBDIR), | |||
false => format!("{}/{}", base_url, RESIZED_SUBDIR), | |||
if base_url.ends_with('/') { | |||
format!("{}{}", base_url, RESIZED_SUBDIR) | |||
} else { | |||
format!("{}/{}", base_url, RESIZED_SUBDIR) | |||
} | |||
} | |||
@@ -236,10 +247,10 @@ impl Processor { | |||
} | |||
pub fn num_img_ops(&self) -> usize { | |||
self.img_ops.len() + self.img_ops_colls.len() | |||
self.img_ops.len() + self.img_ops_collisions.len() | |||
} | |||
fn insert_with_colls(&mut self, mut img_op: ImageOp) -> u32 { | |||
fn insert_with_collisions(&mut self, mut img_op: ImageOp) -> u32 { | |||
match self.img_ops.entry(img_op.hash) { | |||
HEntry::Occupied(entry) => if *entry.get() == img_op { return 0; }, | |||
HEntry::Vacant(entry) => { | |||
@@ -249,37 +260,43 @@ impl Processor { | |||
} | |||
// If we get here, that means a hash collision. | |||
// This is detected when there is an ImageOp with the same hash in the `img_ops` map but which is not equal to this one. | |||
// To deal with this, all collisions get a (random) sequential ID number. | |||
// First try to look up this ImageOp in `img_ops_collisions`, maybe we've already seen the same ImageOp | |||
let mut num = 1; | |||
for op in self.img_ops_colls.iter().filter(|op| op.hash == img_op.hash) { | |||
for op in self.img_ops_collisions.iter().filter(|op| op.hash == img_op.hash) { | |||
if *op == img_op { | |||
// This is a colliding ImageOp, but we've already seen the very same one, so just return its ID | |||
return num; | |||
} else { | |||
num += 1; | |||
} | |||
} | |||
// If we get here, that means this is a new colliding ImageOp and `num` has the next free ID | |||
if num == 1 { | |||
self.img_ops.get_mut(&img_op.hash).unwrap().collision = Some(0); | |||
} | |||
img_op.collision = Some(num); | |||
self.img_ops_colls.push(img_op); | |||
self.img_ops_collisions.push(img_op); | |||
num | |||
} | |||
fn op_filename(hash: u64, colli_num: u32) -> String { | |||
fn op_filename(hash: u64, num_collisions: u32) -> String { | |||
// Please keep this in sync with RESIZED_FILENAME | |||
assert!(colli_num < 256, "Unexpectedly large number of collisions: {}", colli_num); | |||
format!("{:016x}{:02x}.jpg", hash, colli_num) | |||
assert!(num_collisions < 256, "Unexpectedly large number of collisions: {}", num_collisions); | |||
format!("{:016x}{:02x}.jpg", hash, num_collisions) | |||
} | |||
fn op_url(&self, hash: u64, colli_num: u32) -> String { | |||
format!("{}/{}", &self.resized_url, Self::op_filename(hash, colli_num)) | |||
fn op_url(&self, hash: u64, num_collisions: u32) -> String { | |||
format!("{}/{}", &self.resized_url, Self::op_filename(hash, num_collisions)) | |||
} | |||
pub fn insert(&mut self, img_op: ImageOp) -> String { | |||
let hash = img_op.hash; | |||
let num_colli = self.insert_with_colls(img_op); | |||
self.op_url(hash, num_colli) | |||
let num_collisions = self.insert_with_collisions(img_op); | |||
self.op_url(hash, num_collisions) | |||
} | |||
pub fn prune(&self) -> Result<()> { | |||
@@ -291,8 +308,8 @@ impl Processor { | |||
let filename = entry_path.file_name().unwrap().to_string_lossy(); | |||
if let Some(capts) = RESIZED_FILENAME.captures(filename.as_ref()) { | |||
let hash = u64::from_str_radix(capts.get(1).unwrap().as_str(), 16).unwrap(); | |||
let num_colli = u32::from_str_radix(capts.get(2).unwrap().as_str(), 16).unwrap(); | |||
if num_colli > 0 || !self.img_ops.contains_key(&hash) { | |||
let num_collisions = u32::from_str_radix(capts.get(2).unwrap().as_str(), 16).unwrap(); | |||
if num_collisions > 0 || !self.img_ops.contains_key(&hash) { | |||
fs::remove_file(&entry_path)?; | |||
} | |||
} | |||
@@ -303,7 +320,7 @@ impl Processor { | |||
pub fn do_process(&mut self) -> Result<()> { | |||
self.img_ops.par_iter().map(|(hash, op)| { | |||
let target = self.resized_path.join(Self::op_filename(*hash, op.num_colli())); | |||
let target = self.resized_path.join(Self::op_filename(*hash, op.num_collisions())); | |||
op.perform(&self.content_path, &target) | |||
.chain_err(|| format!("Failed to process image: {}", op.source)) | |||
}) | |||
@@ -17,7 +17,7 @@ The function usage is as follows: | |||
- `path`: The path to the source image relative to the `content` directory in the [directory structure](./documentation/getting-started/directory-structure.md). | |||
- `width` and `height`: The dimensions in pixels of the resized image. Usage depends on the `op` argument. | |||
- `op`: Resize operation. This can be one of five choices: `"scale"`, `"fitwidth"`, `"fitheight"`, `"fit"`, or `"fill"`. | |||
- `op`: Resize operation. This can be one of five choices: `"scale"`, `"fit_width"`, `"fit_height"`, `"fit"`, or `"fill"`. | |||
What each of these does is explained below. | |||
This argument is optional, default value is `"fill"`. | |||
- `quality`: JPEG quality of the resized image, in percents. Optional argument, default value is `75`. | |||
@@ -48,24 +48,24 @@ The source for all examples is this 300 × 380 pixels image: | |||
{{ resize_image(path="documentation/content/image-resizing/gutenberg.jpg", width=150, height=150, op="scale") }} | |||
### **`"fitwidth"`** | |||
### **`"fit_width"`** | |||
Resizes the image such that the resulting width is `width` and height is whatever will preserve the aspect ratio. | |||
The `height` argument is not needed. | |||
`resize_image(..., width=100, op="fitwidth")` | |||
`resize_image(..., width=100, op="fit_width")` | |||
{{ resize_image(path="documentation/content/image-resizing/gutenberg.jpg", width=100, height=0, op="fitwidth") }} | |||
{{ resize_image(path="documentation/content/image-resizing/gutenberg.jpg", width=100, height=0, op="fit_width") }} | |||
### **`"fitheight"`** | |||
### **`"fit_height"`** | |||
Resizes the image such that the resulting height is `height` and width is whatever will preserve the aspect ratio. | |||
The `width` argument is not needed. | |||
`resize_image(..., height=150, op="fitheight")` | |||
`resize_image(..., height=150, op="fit_height")` | |||
{{ resize_image(path="documentation/content/image-resizing/gutenberg.jpg", width=0, height=150, op="fitheight") }} | |||
{{ resize_image(path="documentation/content/image-resizing/gutenberg.jpg", width=0, height=150, op="fit_height") }} | |||
### **`"fit"`** | |||
Like `"fitwidth"` and `"fitheight"` combined. | |||
Like `"fit_width"` and `"fit_height"` combined. | |||
Resizes the image such that the result fits within `width` and `height` preserving aspect ratio. This means that both width or height | |||
will be at max `width` and `height`, respectively, but possibly one of them smaller so as to preserve the aspect ratio. | |||
@@ -97,15 +97,15 @@ The examples above were generated using a shortcode file named `resize_image.htm | |||
The `resize_image()` can be used multiple times and/or in loops (it is designed to handle this efficiently). | |||
This can be used along with `assets_imgs` [page metadata](./documentation/templates/pages-sections.md) to create picture galleries. | |||
The `assets_imgs` variable holds paths to all images in the directory of a page with resources | |||
This can be used along with `images` [page metadata](./documentation/templates/pages-sections.md) to create picture galleries. | |||
The `images` variable holds paths to all images in the directory of a page with resources | |||
(see [Assets colocation](./documentation/content/overview.md#assets-colocation)). | |||
This can be used in shortcodes. For example, we can create a very simple html-only clickable | |||
picture gallery with the following shortcode named `gallery.html`: | |||
```jinja2 | |||
{% for img in page.assets_imgs %} | |||
{% for img in page.images %} | |||
<a href="{{ config.base_url }}/{{ img }}"> | |||
<img src="{{ resize_image(path=img, width=240, height=180) }}" /> | |||
</a> | |||
@@ -40,11 +40,11 @@ toc: Array<Header>; | |||
// Paths of colocated assets, relative to the content directory | |||
assets: Array<String>; | |||
// Paths of colocated image assets, ie. files with an extension of "jpg", "jpeg", "png", "gif", or "bmp" | |||
assets_imgs: Array<String>; | |||
images: Array<String>; | |||
``` | |||
## Section variables | |||
By default, Gutenberg will try to load `templates/index.html` for `content/_index.md` | |||
By default, Gutenberg will try to load `templates/index.html` for `content/_index.md` | |||
and `templates/section.html` for others `_index.md` files. If there isn't | |||
one, it will render the built-in template: a blank page. | |||
@@ -1,4 +1,4 @@ | |||
{% for img in page.assets_imgs %} | |||
{% for img in page.images %} | |||
<a href="{{ config.base_url }}/{{ img }}"> | |||
<img src="{{ resize_image(path=img, width=240, height=180, op="fill") }}" /> | |||
</a> | |||