Add thumbnail cache
This commit is contained in:
parent
2c5cd88eb4
commit
da998ccbf1
66
Cargo.lock
generated
66
Cargo.lock
generated
@ -300,6 +300,15 @@ version = "0.1.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block2"
|
name = "block2"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@ -581,6 +590,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.4.2"
|
version = "1.4.2"
|
||||||
@ -657,6 +675,16 @@ version = "0.2.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
|
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "csv"
|
name = "csv"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
@ -750,6 +778,16 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dispatch"
|
name = "dispatch"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -1021,6 +1059,16 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "795cbfc56d419a7ce47ccbb7504dd9a5b7c484c083c356e797de08bd988d9629"
|
checksum = "795cbfc56d419a7ce47ccbb7504dd9a5b7c484c083c356e797de08bd988d9629"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gethostname"
|
name = "gethostname"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
@ -1394,6 +1442,7 @@ dependencies = [
|
|||||||
"libheif-rs",
|
"libheif-rs",
|
||||||
"pollster",
|
"pollster",
|
||||||
"rexiv2",
|
"rexiv2",
|
||||||
|
"sha2",
|
||||||
"threadpool",
|
"threadpool",
|
||||||
"winit",
|
"winit",
|
||||||
"zune-image",
|
"zune-image",
|
||||||
@ -2804,6 +2853,17 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@ -3181,6 +3241,12 @@ dependencies = [
|
|||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
|
@ -21,6 +21,7 @@ itertools = "0.12"
|
|||||||
rexiv2 = "0.10.0"
|
rexiv2 = "0.10.0"
|
||||||
threadpool = "1.8.1"
|
threadpool = "1.8.1"
|
||||||
bytemuck = "1.22.0"
|
bytemuck = "1.22.0"
|
||||||
|
sha2 = "0.10.8"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
172
src/image.rs
172
src/image.rs
@ -8,17 +8,26 @@ use jpegxl_rs::decode::PixelFormat;
|
|||||||
use jpegxl_rs::decoder_builder;
|
use jpegxl_rs::decoder_builder;
|
||||||
use libheif_rs::{HeifContext, LibHeif, RgbChroma};
|
use libheif_rs::{HeifContext, LibHeif, RgbChroma};
|
||||||
use rexiv2::Metadata;
|
use rexiv2::Metadata;
|
||||||
|
use sha2::Digest;
|
||||||
|
use sha2::Sha256;
|
||||||
|
use sha2::digest::consts::U32;
|
||||||
|
use sha2::digest::generic_array::GenericArray;
|
||||||
use zune_image::codecs::jpeg::JpegDecoder;
|
use zune_image::codecs::jpeg::JpegDecoder;
|
||||||
use zune_image::codecs::qoi::zune_core::colorspace::ColorSpace;
|
use zune_image::codecs::qoi::zune_core::colorspace::ColorSpace;
|
||||||
use zune_image::codecs::qoi::zune_core::options::DecoderOptions;
|
use zune_image::codecs::qoi::zune_core::options::DecoderOptions;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::fs::read;
|
use std::fs::read;
|
||||||
|
use std::hash::Hash;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::io::Write;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::str::FromStr;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
#[derive(Clone, Eq, Hash, PartialEq, PartialOrd)]
|
#[derive(Clone, Eq, Hash, PartialEq, PartialOrd)]
|
||||||
@ -28,14 +37,43 @@ pub enum ImageFormat {
|
|||||||
Heif,
|
Heif,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Eq, Hash, PartialEq)]
|
#[derive(Clone)]
|
||||||
pub struct ImageData {
|
pub struct ImageData {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
pub format: ImageFormat,
|
pub format: ImageFormat,
|
||||||
pub embedded_thumbnail: bool,
|
pub embedded_thumbnail: bool,
|
||||||
pub orientation: Orientation,
|
pub orientation: Orientation,
|
||||||
|
pub hash: GenericArray<u8, U32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ImageData {
|
||||||
|
pub fn get_cache_path(&self) -> PathBuf {
|
||||||
|
let home_dir = PathBuf::from_str(&env::var("HOME").unwrap()).unwrap();
|
||||||
|
let cache_dir = home_dir.join(".cache/imflow");
|
||||||
|
if !cache_dir.exists() {
|
||||||
|
fs::create_dir(&cache_dir).unwrap();
|
||||||
|
}
|
||||||
|
let hash_hex = format!("{:x}", self.hash);
|
||||||
|
return cache_dir.join(hash_hex).to_path_buf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for ImageData {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
state.write(self.path.to_str().unwrap().as_bytes());
|
||||||
|
state.write(self.hash.as_slice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for ImageData {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.hash.eq(&other.hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for ImageData {}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct ImflowImageBuffer {
|
pub struct ImflowImageBuffer {
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
@ -213,14 +251,23 @@ pub fn load_available_images(dir: PathBuf) -> Vec<ImageData> {
|
|||||||
if let Some(format) = get_format(&path) {
|
if let Some(format) = get_format(&path) {
|
||||||
let meta = Metadata::new_from_path(&path)
|
let meta = Metadata::new_from_path(&path)
|
||||||
.expect(&format!("Image has no metadata: {:?}", path).to_string());
|
.expect(&format!("Image has no metadata: {:?}", path).to_string());
|
||||||
let embedded_thumbnail = meta.get_preview_images().is_some();
|
let embedded_thumbnail = if format == ImageFormat::Heif {
|
||||||
|
let ctx = HeifContext::read_from_file(path.to_str().unwrap()).unwrap();
|
||||||
|
let binding = ctx.top_level_image_handles();
|
||||||
|
let handle = binding.get(0).unwrap();
|
||||||
|
handle.number_of_thumbnails() > 0
|
||||||
|
} else {
|
||||||
|
meta.get_preview_images().is_some()
|
||||||
|
};
|
||||||
let orientation = Orientation::from_exif(meta.get_orientation() as u8)
|
let orientation = Orientation::from_exif(meta.get_orientation() as u8)
|
||||||
.unwrap_or(Orientation::NoTransforms);
|
.unwrap_or(Orientation::NoTransforms);
|
||||||
|
let hash = get_file_hash(&path);
|
||||||
Some(ImageData {
|
Some(ImageData {
|
||||||
path,
|
path,
|
||||||
format,
|
format,
|
||||||
embedded_thumbnail,
|
embedded_thumbnail,
|
||||||
orientation,
|
orientation,
|
||||||
|
hash,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -253,13 +300,39 @@ pub fn get_embedded_thumbnail(image: &ImageData) -> Option<Vec<u8>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_thumbnail(path: &ImageData) -> ImflowImageBuffer {
|
pub fn load_thumbnail(path: &ImageData) -> ImflowImageBuffer {
|
||||||
if path.format == ImageFormat::Heif {
|
let cache_path = path.get_cache_path();
|
||||||
return load_heif(path, true);
|
if cache_path.exists() {
|
||||||
}
|
let bytes = fs::read(cache_path).unwrap();
|
||||||
match load_thumbnail_exif(path) {
|
let width = u32::from_le_bytes(bytes[..4].try_into().unwrap()) as usize;
|
||||||
Some(thumbnail) => return thumbnail,
|
let height = u32::from_le_bytes(bytes[4..8].try_into().unwrap()) as usize;
|
||||||
None => load_thumbnail_full(path),
|
let buffer: &[u8] = &bytes[8..];
|
||||||
|
let mut buffer_u8 = buffer.to_vec();
|
||||||
|
let buffer_u32 = unsafe {
|
||||||
|
Vec::from_raw_parts(
|
||||||
|
buffer_u8.as_mut_ptr() as *mut u32,
|
||||||
|
buffer_u8.len() / 4,
|
||||||
|
buffer_u8.len() / 4,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
std::mem::forget(buffer_u8);
|
||||||
|
|
||||||
|
assert_eq!(width * height, buffer_u32.len());
|
||||||
|
|
||||||
|
return ImflowImageBuffer {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
rgba_buffer: buffer_u32,
|
||||||
|
rating: 0,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
let thumbnail = if path.format == ImageFormat::Heif {
|
||||||
|
load_heif(path, true)
|
||||||
|
} else {
|
||||||
|
load_thumbnail_exif(path).unwrap_or(load_thumbnail_full(path))
|
||||||
|
};
|
||||||
|
|
||||||
|
save_thumbnail(&cache_path, thumbnail.clone());
|
||||||
|
thumbnail
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_thumbnail_exif(path: &ImageData) -> Option<ImflowImageBuffer> {
|
pub fn load_thumbnail_exif(path: &ImageData) -> Option<ImflowImageBuffer> {
|
||||||
@ -268,8 +341,9 @@ pub fn load_thumbnail_exif(path: &ImageData) -> Option<ImflowImageBuffer> {
|
|||||||
let decoder = image::ImageReader::new(Cursor::new(thumbnail))
|
let decoder = image::ImageReader::new(Cursor::new(thumbnail))
|
||||||
.with_guessed_format()
|
.with_guessed_format()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let image = decoder.decode().unwrap();
|
let mut image = decoder.decode().unwrap();
|
||||||
|
|
||||||
|
image.apply_orientation(path.orientation);
|
||||||
let width: usize = image.width() as usize;
|
let width: usize = image.width() as usize;
|
||||||
let height: usize = image.height() as usize;
|
let height: usize = image.height() as usize;
|
||||||
let flat = image.into_rgba8().into_raw();
|
let flat = image.into_rgba8().into_raw();
|
||||||
@ -281,6 +355,7 @@ pub fn load_thumbnail_exif(path: &ImageData) -> Option<ImflowImageBuffer> {
|
|||||||
buffer.len() / 4,
|
buffer.len() / 4,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
std::mem::forget(buffer);
|
||||||
|
|
||||||
let rating = get_rating(path.into());
|
let rating = get_rating(path.into());
|
||||||
|
|
||||||
@ -303,7 +378,7 @@ pub fn load_thumbnail_full(path: &ImageData) -> ImflowImageBuffer {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.decode()
|
.decode()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.resize(640, 480, FilterType::Nearest);
|
.resize_to_fill(1920, 1920, FilterType::Lanczos3);
|
||||||
let width = image.width() as usize;
|
let width = image.width() as usize;
|
||||||
let height = image.height() as usize;
|
let height = image.height() as usize;
|
||||||
let buffer = image_to_rgba_buffer(image);
|
let buffer = image_to_rgba_buffer(image);
|
||||||
@ -320,25 +395,47 @@ pub fn load_thumbnail_full(path: &ImageData) -> ImflowImageBuffer {
|
|||||||
pub fn load_heif(path: &ImageData, resize: bool) -> ImflowImageBuffer {
|
pub fn load_heif(path: &ImageData, resize: bool) -> ImflowImageBuffer {
|
||||||
let lib_heif = LibHeif::new();
|
let lib_heif = LibHeif::new();
|
||||||
let ctx = HeifContext::read_from_file(path.path.to_str().unwrap()).unwrap();
|
let ctx = HeifContext::read_from_file(path.path.to_str().unwrap()).unwrap();
|
||||||
let handle = ctx.primary_image_handle().unwrap();
|
|
||||||
let mut image = lib_heif
|
let image = if resize {
|
||||||
.decode(&handle, libheif_rs::ColorSpace::Rgb(RgbChroma::Rgba), None)
|
let binding = ctx.top_level_image_handles();
|
||||||
.unwrap();
|
let handle = binding.get(0).unwrap();
|
||||||
|
let thumbnail_count = handle.number_of_thumbnails() as u32;
|
||||||
|
let mut thumbnail_ids = vec![0u32, thumbnail_count];
|
||||||
|
handle.thumbnail_ids(&mut thumbnail_ids);
|
||||||
|
let handle = &handle.thumbnail(thumbnail_ids[0]).unwrap();
|
||||||
|
|
||||||
|
lib_heif
|
||||||
|
.decode(handle, libheif_rs::ColorSpace::Rgb(RgbChroma::Rgba), None)
|
||||||
|
.unwrap()
|
||||||
|
} else {
|
||||||
|
let binding = ctx.top_level_image_handles();
|
||||||
|
let handle = binding.get(0).unwrap();
|
||||||
|
|
||||||
|
lib_heif
|
||||||
|
.decode(handle, libheif_rs::ColorSpace::Rgb(RgbChroma::Rgba), None)
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
image.color_space(),
|
image.color_space(),
|
||||||
Some(libheif_rs::ColorSpace::Rgb(RgbChroma::Rgba)),
|
Some(libheif_rs::ColorSpace::Rgb(RgbChroma::Rgba)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Scale the image
|
|
||||||
if resize {
|
|
||||||
image = image.scale(640, 480, None).unwrap();
|
|
||||||
assert_eq!(image.width(), 640);
|
|
||||||
assert_eq!(image.height(), 480);
|
|
||||||
}
|
|
||||||
|
|
||||||
let width = image.width() as usize;
|
let width = image.width() as usize;
|
||||||
let height = image.height() as usize;
|
let height = image.height() as usize;
|
||||||
|
|
||||||
|
// Scale the image
|
||||||
|
// if resize {
|
||||||
|
// const MAX: usize = 3000;
|
||||||
|
// let scale = max(width, height) as f32 / MAX as f32;
|
||||||
|
// width = (width as f32 / scale) as usize;
|
||||||
|
// height = (height as f32 / scale) as usize;
|
||||||
|
// // image = image.scale(width as u32, height as u32, None).unwrap();
|
||||||
|
// image = image.scale(599, 300, None).unwrap();
|
||||||
|
// width = image.width() as usize;
|
||||||
|
// height = image.height() as usize;
|
||||||
|
// }
|
||||||
|
|
||||||
let rating = get_rating(path);
|
let rating = get_rating(path);
|
||||||
|
|
||||||
// Get "pixels"
|
// Get "pixels"
|
||||||
@ -346,6 +443,7 @@ pub fn load_heif(path: &ImageData, resize: bool) -> ImflowImageBuffer {
|
|||||||
let interleaved_plane = planes.interleaved.unwrap();
|
let interleaved_plane = planes.interleaved.unwrap();
|
||||||
assert!(!interleaved_plane.data.is_empty());
|
assert!(!interleaved_plane.data.is_empty());
|
||||||
assert!(interleaved_plane.stride > 0);
|
assert!(interleaved_plane.stride > 0);
|
||||||
|
assert_eq!(interleaved_plane.storage_bits_per_pixel, 32);
|
||||||
|
|
||||||
let rgba_buffer = interleaved_plane.data;
|
let rgba_buffer = interleaved_plane.data;
|
||||||
let u32_slice = unsafe {
|
let u32_slice = unsafe {
|
||||||
@ -359,3 +457,35 @@ pub fn load_heif(path: &ImageData, resize: bool) -> ImflowImageBuffer {
|
|||||||
rating,
|
rating,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_file_hash(path: &PathBuf) -> GenericArray<u8, U32> {
|
||||||
|
let mut file = File::open(path).unwrap();
|
||||||
|
let mut buf = [0u8; 16 * 1024];
|
||||||
|
file.read(&mut buf).unwrap();
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
hasher.update(&buf);
|
||||||
|
hasher.update(file.metadata().unwrap().len().to_le_bytes());
|
||||||
|
hasher.finalize()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: optimize
|
||||||
|
pub fn save_thumbnail(path: &PathBuf, image: ImflowImageBuffer) {
|
||||||
|
let cache_dir = path.parent().unwrap();
|
||||||
|
if !cache_dir.exists() {
|
||||||
|
fs::create_dir(cache_dir).unwrap();
|
||||||
|
}
|
||||||
|
println!("path: {:?}", path);
|
||||||
|
let mut file = File::create(path).unwrap();
|
||||||
|
let buffer = image.rgba_buffer;
|
||||||
|
let u8_buffer = unsafe {
|
||||||
|
Vec::from_raw_parts(
|
||||||
|
buffer.as_ptr() as *mut u8,
|
||||||
|
buffer.len() * 4,
|
||||||
|
buffer.len() * 4,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
std::mem::forget(buffer);
|
||||||
|
file.write(&(image.width as u32).to_le_bytes()).unwrap();
|
||||||
|
file.write(&(image.height as u32).to_le_bytes()).unwrap();
|
||||||
|
file.write(&u8_buffer).unwrap();
|
||||||
|
}
|
||||||
|
@ -171,6 +171,7 @@ impl ImageStore {
|
|||||||
.get(&self.current_image_path)
|
.get(&self.current_image_path)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
// panic!();
|
||||||
|
|
||||||
let buf = load_thumbnail(&self.current_image_path);
|
let buf = load_thumbnail(&self.current_image_path);
|
||||||
self.loaded_images_thumbnails
|
self.loaded_images_thumbnails
|
||||||
|
Loading…
x
Reference in New Issue
Block a user