fast image operations
Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 970 |
1 files changed, 134 insertions, 836 deletions
@@ -1,370 +1,114 @@ -//! # fimg -//! -//! Provides fast image operations, such as rotation, flipping, and overlaying. -//! -//! ## Organization -//! -//! Image types: -//! -//! - [`Image`]: the main image type. -//! - [`DynImage`]: This is the image type you use when, say, loading a png. You should immediately convert this into a -//! - [`ImageCloner`]: This is... a [`Image`], but about to be cloned. It just allows some simple out-of-place optimizations, that `.clone().op()` dont allow. (produce with [`Image::cloner`]) -//! - [`uninit::Image`]: A uninitialized image. Used for performance optimization. -//! -//! ### Operations -//! -//! Affine: -//! - [`Image::rot_90`] -//! - [`Image::rot_180`] -//! - [`Image::rot_270`] -//! - [`Image::flip_h`] -//! - [`Image::flip_v`] -//! -//! Drawing: -//! - [`Image::box`], [`Image::filled_box`], [`Image::stroked_box`] -//! - [`Image::circle`], [`Image::border_circle`] -//! - [`Image::line`], [`Image::thick_line`] -//! - [`Image::points`] -//! - [`Image::quad`] -//! - [`Image::poly`], [`Image::border_poly`] -//! - [`Image::tri`] -//! - [`Image::text`] -//! -//! Scaling: [`Image::scale`] -//! -//! Misc image ops: -//! - [`Image::repeated`] -//! - [`Image::overlay`](Overlay), [`Image::overlay_at`](OverlayAt), [`Image::overlay_blended`](BlendingOverlay) -//! - [`Image::blur`] -//! - [`Image::crop`] -//! -//! ## feature flags -//! -//! - `scale`: enables the [`scale`] module. -//! - `save`: enables [`Image::save`], via the [`png`](https://crates.io/crates/png) crate. -//! - `text`: enables [`Image::text`], via the [`fontdue`](https://crates.io/crates/fontdue) crate. -//! - `blur`: enables [`Image::blur`], via the [`stackblur`](https://crates.io/crates/stackblur-iter) crate. -//! - `real-show`: [`Image::show`], if the `save` feature is enabled, will, by default, simply open the appropriate image viewing program. -//! if, for some reason, this is inadequate/you dont have a good image viewer, enable the `real-show` feature to make [`Image::show`] open up a window of its own. -//! without the `real-show` feature, [`Image::show`] will save itself to your temp directory, which you may not want. -//! - `term`: [`term::print`]. this enables printing images directly to the terminal, if you don't want to open a window or something. supports `{iterm2, kitty, sixel, fallback}` graphics. -//! - `default`: \[`save`, `scale`\]. -#![cfg_attr(all(feature = "term", windows), windows_subsystem = "console")] #![feature( - type_changing_struct_update, - custom_inner_attributes, slice_swap_unchecked, - generic_const_exprs, - proc_macro_hygiene, - iter_array_chunks, - const_trait_impl, - core_intrinsics, - new_range_api, - rustc_private, + slice_as_chunks, + unchecked_math, portable_simd, - const_convert, - try_blocks, - doc_cfg, + array_chunks, test )] #![warn( - clippy::undocumented_unsafe_blocks, + clippy::multiple_unsafe_ops_per_block, clippy::missing_const_for_fn, clippy::missing_safety_doc, - clippy::suboptimal_flops, unsafe_op_in_unsafe_fn, clippy::dbg_macro, - clippy::use_self, - missing_docs + clippy::perf )] -#![allow( - clippy::zero_prefixed_literal, - mixed_script_confusables, - incomplete_features, - confusable_idents, - internal_features -)] -use array_chunks::*; -use hinted::HintExt; -use std::{hint::assert_unchecked, intrinsics::transmute_unchecked, num::NonZeroU32, ops::Range}; +#![allow(clippy::zero_prefixed_literal)] + +use std::{num::NonZeroU32, slice::SliceIndex}; mod affine; -#[cfg(feature = "blur")] -mod blur; -mod slicing; -pub use sub::{Cropper, SubImage}; -pub mod builder; -#[doc(hidden)] -pub mod cloner; -mod convert; -mod drawing; -mod r#dyn; -pub mod indexed; -pub(crate) mod math; -#[doc(hidden)] -pub mod overlay; -mod pack; -mod span; -mod sub; -pub mod uninit; -#[cfg(feature = "wgpu-convert")] -mod wgpu_convert; -pub use pack::Pack; -pub mod pixels; -#[cfg(feature = "scale")] -pub mod scale; -#[cfg(any(feature = "save", feature = "real-show"))] -mod show; -#[cfg(feature = "term")] -pub mod term; -pub use cloner::ImageCloner; -pub use r#dyn::DynImage; -pub use overlay::{ - BlendingOverlay, BlendingOverlayAt, ClonerOverlay, ClonerOverlayAt, Overlay, OverlayAt, - OverlayAtClipping, -}; +mod overlay; +pub use affine::{Flips, Rotations}; +pub use overlay::{Overlay, OverlayAt}; -trait CopyWithinUnchecked { +pub trait RepeatNew { + type Output; + /// Repeat self till it fills a new image of size x, y /// # Safety /// - /// panicless version of [`[T]::copy_within`](`slice::copy_within`), where the slices cant overlap. this uses `memcpy`. - /// your slices must be in bounds. - /// this isnt a public function, so im not going to say exactly what "in bounds" means. - unsafe fn copy_within_unchecked(&mut self, src: Range<usize>, dest: usize); -} - -impl<T> CopyWithinUnchecked for [T] { - unsafe fn copy_within_unchecked(&mut self, src: Range<usize>, dest: usize) { - let std::ops::Range { start, end } = src; - debug_assert!(dest <= self.len() - end - start, "dest is out of bounds"); - #[allow(clippy::multiple_unsafe_ops_per_block)] - // SAFETY: the caller better be good - unsafe { - let ptr = self.as_mut_ptr(); - std::ptr::copy_nonoverlapping(ptr.add(start), ptr.add(dest), end - start) - }; - } -} - -trait At { - fn at<const C: usize>(self, x: u32, y: u32) -> usize; + /// UB if self's width is not a multiple of x, or self's height is not a multiple of y + unsafe fn repeated(&self, x: u32, y: u32) -> Self::Output; } -impl At for (u32, u32) { - #[inline] - fn at<const C: usize>(self, x: u32, y: u32) -> usize { - #[allow(clippy::multiple_unsafe_ops_per_block)] - // SAFETY: me when uncheck math: 😧 (FIXME) - let index = unsafe { - // y * w + x - let tmp = (y as usize).unchecked_mul(self.0 as usize); - tmp.unchecked_add(x as usize) - }; - // SAFETY: 🧐 is unsound? 😖 - unsafe { index.unchecked_mul(C) } - } +macro_rules! assert_unchecked { + ($cond:expr) => {{ + if !$cond { + #[cfg(debug_assertions)] + let _ = ::core::ptr::NonNull::<()>::dangling().as_ref(); // force unsafe wrapping block + #[cfg(debug_assertions)] + panic!("assertion failed: {} returned false", stringify!($cond)); + #[cfg(not(debug_assertions))] + std::hint::unreachable_unchecked() + } + }}; } - -impl<T: AsRef<[u8]>> Image<T, 3> { - /// Tile self till it fills a new image of size x, y - /// # Safety - /// - /// UB if self's width is not a multiple of x, or self's height is not a multiple of y - /// ``` - /// # use fimg::Image; - /// let x: Image<&[u8], 3> = Image::build(8, 8).buf(include_bytes!("../benches/3_8x8.imgbuf")); - /// let tiled = unsafe { x.repeated(48, 48) }; // repeat 6 times - /// # assert_eq!(tiled.buffer(), b"\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xf7\xcb\xa4\xf7\xcb\xa4\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d\xd3\xae\x8d") - /// ``` - #[must_use = "function does not modify the original image"] - pub unsafe fn repeated(&self, out_width: u32, out_height: u32) -> Image<Vec<u8>, 3> { - let mut img = uninit::Image::new( - out_width.try_into().unwrap(), - out_height.try_into().unwrap(), - ); - debug_assert!(out_width % self.width() == 0); - debug_assert!(out_height % self.height() == 0); - for y in 0..self.height() { - // SAFETY: get one row of pixels - let from = unsafe { - self.buffer - .as_ref() - .get_unchecked(self.at(0, y)..self.at(0, y) + (self.width() as usize * 3)) - }; - debug_assert_eq!(from.len(), self.width() as usize * 3); - let first = (0, y)..(self.width(), y); - // SAFETY: copy it in - unsafe { img.write(from, first.clone()) }; - - for x in 1..(out_width / self.width()) { - let section = img.at(x * self.width(), y); - // SAFETY: copy each row of the image one by one - unsafe { img.copy_within(first.clone(), section) }; +use assert_unchecked; + +impl RepeatNew for Image<&[u8], 3> { + type Output = Image<Vec<u8>, 3>; + unsafe fn repeated(&self, x: u32, y: u32) -> Self::Output { + let mut img = Image::alloc(x, y); // could probably optimize this a ton but eh + for x in 0..(x / self.width()) { + for y in 0..(y / self.height()) { + let a: &mut Image<&mut [u8], 3> = &mut img.as_mut(); + // SAFETY: caller upholds + unsafe { a.overlay_at(self, x * self.width(), y * self.height()) }; } } - let first_row = 0..img.at(0, self.height()); - for y in 1..(out_height / self.height()) { - let this_row = img.at(0, y * self.height()); - // SAFETY: copy entire blocks of image at a time - unsafe { img.copy_within(first_row.clone(), this_row) }; - } - // SAFETY: we init - unsafe { img.assume_init() } + img } } -/// A image with a variable number of channels, and a nonzero size. -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(C)] +#[inline] +unsafe fn really_unsafe_index(x: u32, y: u32, w: u32) -> usize { + // y * w + x + let tmp = unsafe { (y as usize).unchecked_mul(w as usize) }; + unsafe { tmp.unchecked_add(x as usize) } +} + +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Image<T, const CHANNELS: usize> { - /// column order 2d slice/vec - buffer: T, - /// image horizontal size - width: NonZeroU32, - /// image vertical size - height: NonZeroU32, + pub buffer: T, + pub width: NonZeroU32, + pub height: NonZeroU32, } -impl<T: Clone, const CHANNELS: usize> Clone for Image<T, CHANNELS> { - /// Returns a duplicate of this image. - /// ``` - /// # use fimg::Image; - /// # let i = Image::<Vec<_>, 1>::alloc(5,5); - /// let new_i = i.clone(); - /// ``` - /// If you find yourself in the pattern of - /// ``` - /// # use fimg::Image; - /// # let i = Image::<Vec<_>, 1>::alloc(5,5); - /// let mut i = i.clone(); - /// unsafe { i.rot_90() }; - /// ``` - /// STOP! - /// - /// Instead use - /// ``` - /// # use fimg::Image; - /// # let i = Image::<Vec<_>, 1>::alloc(5,5); - /// let i = unsafe { i.cloner().rot_90() }; - /// ``` - fn clone(&self) -> Self { +impl<const CHANNELS: usize> Default for Image<&'static [u8], CHANNELS> { + fn default() -> Self { Self { - buffer: self.buffer.clone(), - width: self.width, - height: self.height, + buffer: &[0; CHANNELS], + width: NonZeroU32::new(1).unwrap(), + height: NonZeroU32::new(1).unwrap(), } } } impl<T, const CHANNELS: usize> Image<T, CHANNELS> { - #[doc(hidden)] - pub const fn channels(&self) -> usize { - CHANNELS - } - #[inline] - /// get the height as a [`u32`] - pub const fn height(&self) -> u32 { - self.height.get() + pub fn height(&self) -> u32 { + self.height.into() } #[inline] - /// get the width as a [`u32`] - pub const fn width(&self) -> u32 { - self.width.get() + pub fn width(&self) -> u32 { + self.width.into() } #[inline] - /// create a new image - /// - /// # Safety - /// - /// does not check that buffer.len() == w * h * C - /// - /// using this with invalid values may result in future UB - pub const unsafe fn new(width: NonZeroU32, height: NonZeroU32, buffer: T) -> Self { - Self { + pub const fn new(width: NonZeroU32, height: NonZeroU32, buffer: T) -> Self { + Image { buffer, width, height, } } - - /// consumes the image, returning the image buffer - pub fn take_buffer(self) -> T { - self.buffer - } - - /// returns a immutable reference to the backing buffer - pub const fn buffer(&self) -> &T { - &self.buffer - } - - /// returns a mutable(!) reference to the backing buffer - /// - /// # Safety - /// - /// please do not change buffer size. - pub unsafe fn buffer_mut(&mut self) -> &mut T { - &mut self.buffer - } - - /// # Safety - /// - /// the output index is not guaranteed to be in bounds - #[inline] - #[cfg_attr(debug_assertions, track_caller)] - pub fn at(&self, x: u32, y: u32) -> usize { - (self.width(), self.height()).at::<CHANNELS>(x, y) - } - - /// # Safety - /// keep the buffer size the same - unsafe fn with<U, const N: usize>(&self, x: U) -> Image<U, N> { - unsafe { Image::new(self.width, self.height, x) } - } - - /// # Safety - /// keep the buffer size the same - unsafe fn map<U, const N: usize, F: FnOnce(&T) -> U>(&self, f: F) -> Image<U, N> { - // SAFETY: we dont change anything, why check - unsafe { self.with(f(self.buffer())) } - } - #[doc(hidden)] - pub unsafe fn mapped<U, const N: usize, F: FnOnce(T) -> U>(self, f: F) -> Image<U, N> { - // SAFETY: we dont change anything, why check - unsafe { Image::new(self.width, self.height, f(self.buffer)) } - } - - /// # Safety - /// buffer size must be the same. - unsafe fn map_into<U: From<T>, const N: usize>(self) -> Image<U, N> { - unsafe { self.mapped(Into::into) } - } } -impl<const CHANNELS: usize, T: Clone> Image<&[T], CHANNELS> { - /// Allocate a new `Image<Vec<T>>` from this imageref. - pub fn to_owned(&self) -> Image<Vec<T>, CHANNELS> { - // SAFETY: size not changed - unsafe { self.map(|b| b.to_vec()) } - } -} - -impl<const CHANNELS: usize, T: Clone> Image<&mut [T], CHANNELS> { - /// Allocate a new `Image<Vec<T>>` from this mutable imageref. - pub fn to_owned(&self) -> Image<Vec<T>, CHANNELS> { - // SAFETY: size not changed - unsafe { self.map(|b| b.to_vec()) } - } -} - -impl<const CHANNELS: usize> Copy for Image<&[u8], CHANNELS> {} - impl<const CHANNELS: usize> Image<&[u8], CHANNELS> { #[inline] #[must_use] - /// Copy this ref image pub const fn copy(&self) -> Self { Self { width: self.width, @@ -372,179 +116,31 @@ impl<const CHANNELS: usize> Image<&[u8], CHANNELS> { buffer: self.buffer, } } - - /// Create a new immutable image of width x, y. - /// - /// # Panics - /// - /// if width || height == 0 - /// - /// ``` - /// # use fimg::Image; - /// let img = Image::make::<5, 5>(); - /// # let img: Image<_, 4> = img; - /// ``` - pub const fn make<'a, const WIDTH: u32, const HEIGHT: u32>() -> Image<&'a [u8], CHANNELS> - where - [(); CHANNELS * WIDTH as usize * HEIGHT as usize]:, - { - Image { - width: NonZeroU32::new(WIDTH).expect("passed zero width to builder"), - height: NonZeroU32::new(HEIGHT).expect("passed zero height to builder"), - buffer: &[0; CHANNELS * WIDTH as usize * HEIGHT as usize], - } - } -} - -impl<const CHANNELS: usize, const N: usize, T> Image<[T; N], CHANNELS> { - /// Box this array image. - pub fn boxed(self) -> Image<Box<[T]>, CHANNELS> { - // SAFETY: size not changed - unsafe { self.map_into() } - } } -impl<const CHANNELS: usize, T: Copy> Image<&[T], CHANNELS> { - /// Box this image. - pub fn boxed(self) -> Image<Box<[T]>, CHANNELS> { - // SAFETY: size not changed - unsafe { self.map_into() } - } -} - -impl<const CHANNELS: usize, T> Image<Vec<T>, CHANNELS> { - /// Box this owned image. - pub fn boxed(self) -> Image<Box<[T]>, CHANNELS> { - // SAFETY: ctor - unsafe { self.map_into() } - } -} - -impl<const CHANNELS: usize, T> Image<Box<[T]>, CHANNELS> { - /// Unbox this vec image. - pub fn unbox(self) -> Image<Vec<T>, CHANNELS> { - // SAFETY: ctor - unsafe { self.map_into() } - } -} - -#[macro_export] -/// Create a <code>[Image]<[[u8]; N], C></code> with ease. If your looking for a <code>[Image]<&'static [[u8]]></code>, try [`Image::make`]. -/// -/// ``` -/// let mut i = fimg::make!(4 channels 128 x 128); -/// ``` -/// -/// Implementation note: -/// This is doable with a const generic fn, but it returns a `fimg::Image<[u8; fimg::::{impl#7}::array::{constant#1}], _>` which means you cant actually type it, so its useless. -macro_rules! make { - ($channels:literal channels $w:literal x $h: literal) => { - unsafe { - $crate::Image::<_, $channels>::new( - match ::core::num::NonZeroU32::new($w) { - ::core::option::Option::Some(n) => n, - ::core::option::Option::None => panic!("width is 0"), - }, - match ::core::num::NonZeroU32::new($h) { - ::core::option::Option::Some(n) => n, - ::core::option::Option::None => panic!("height is 0"), - }, - [0_u8; $channels * $w * $h], - ) - } - }; -} - -impl<T, const CHANNELS: usize> Image<T, CHANNELS> { - /// The size of the underlying buffer. - #[allow(clippy::len_without_is_empty)] - pub fn len<U>(&self) -> usize - where - T: AsRef<[U]>, - { - self.buffer().as_ref().len() - } - - /// Transforms the N - /// - /// # Safety - /// - /// i think you can see why this is a problem. - /// - /// # WHY??? - /// - /// sometimes rust is silly with generics - unsafe fn trans<const N: usize>(self) -> Image<T, N> { - unsafe { transmute_unchecked(self) } - } +impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> { /// # Safety /// - /// the output index is not guaranteed to be in bounds + /// - UB if x, y is out of bounds + /// - UB if buffer is too small #[inline] - fn slice<U>(&self, x: u32, y: u32) -> Range<usize> - where - T: AsRef<[U]>, - { - let index = self.at(x, y); - // SAFETY: as long as the buffer isnt wrong, this is 😄 + unsafe fn slice(&self, x: u32, y: u32) -> impl SliceIndex<[u8], Output = [u8]> { + debug_assert!(x < self.width(), "x out of bounds"); + debug_assert!(y < self.height(), "y out of bounds"); + let index = unsafe { really_unsafe_index(x, y, self.width()) }; + let index = unsafe { index.unchecked_mul(CHANNELS) }; + debug_assert!(self.buffer.len() > index); index..unsafe { index.unchecked_add(CHANNELS) } } #[inline] /// Returns a iterator over every pixel - pub fn chunked<'a, U: 'a>( - &'a self, - ) -> impl DoubleEndedIterator<Item = &'a [U; CHANNELS]> + ExactSizeIterator - where - T: AsRef<[U]>, - { + pub fn chunked(&self) -> impl Iterator<Item = &[u8; CHANNELS]> { // SAFETY: 0 sized images illegal - unsafe { assert_unchecked(self.len() >= CHANNELS) }; + unsafe { assert_unchecked!(self.buffer.len() > CHANNELS) }; // SAFETY: no half pixels! - unsafe { assert_unchecked(self.len() % CHANNELS == 0) }; - self.buffer().as_ref().array_chunks::<CHANNELS>() - } - - #[inline] - /// Flatten the chunks of this image into a slice of slices. - pub fn flatten<U>(&self) -> &[[U; CHANNELS]] - where - T: AsRef<[U]>, - { - // SAFETY: buffer cannot have half pixels - unsafe { self.buffer().as_ref().as_chunks_unchecked::<CHANNELS>() } - } - - /// Create a mutref to this image - pub fn as_mut<U>(&mut self) -> Image<&mut [U], CHANNELS> - where - T: AsMut<[U]>, - { - // SAFETY: construction went okay - unsafe { Image::new(self.width, self.height, self.buffer.as_mut()) } - } - - /// Reference this image. - pub fn as_ref<U>(&self) -> Image<&[U], CHANNELS> - where - T: AsRef<[U]>, - { - // SAFETY: we got constructed okay, parameters must be valid - unsafe { Image::new(self.width, self.height, self.buffer().as_ref()) } - } - - /// Get a pixel. Optionally. Yeah! - pub fn get_pixel<U>(&self, x: u32, y: u32) -> Option<&[U; CHANNELS]> - where - T: AsRef<[U]>, - { - ((x < self.width()) & (y < self.height())).then(|| unsafe { - self.buffer() - .as_ref() - .get_unchecked(self.slice(x, y)) - .as_array() - .unwrap_unchecked() - }) + unsafe { assert_unchecked!(self.buffer.len() % CHANNELS == 0) }; + self.buffer.array_chunks::<CHANNELS>() } /// Return a pixel at (x, y). @@ -553,240 +149,33 @@ impl<T, const CHANNELS: usize> Image<T, CHANNELS> { /// - UB if x, y is out of bounds /// - UB if buffer is too small #[inline] - pub unsafe fn pixel<U>(&self, x: u32, y: u32) -> &[U; CHANNELS] - where - T: AsRef<[U]>, - { - debug_assert!(x < self.width()); - debug_assert!(y < self.height()); - - // SAFETY: x and y in bounds - unsafe { self.get_pixel(x, y).unwrap_unchecked() } - } - - /// pixels contiguously from start to end - /// they gotta be in bounds - /// - /// i think this is unsound because you can make asref do whatever the fucking fuck you fucking want but thats fucking on you - pub unsafe fn pixels<U: Copy>(&self, r: impl PBounds) -> &[[U; CHANNELS]] - where - T: AsRef<[U]>, - { - let b = self.bounds(r); - unsafe { self.buffer.as_ref().get_unchecked(b).as_chunks_unchecked() } - } - /// pixels contiguously from start to end - pub unsafe fn pixels_mut<U: Copy>(&mut self, r: impl PBounds) -> &mut [[U; CHANNELS]] - where - T: AsRef<[U]> + AsMut<[U]>, - { - let b = self.bounds(r); - unsafe { - self.buffer - .as_mut() - .get_unchecked_mut(b) - .as_chunks_unchecked_mut() - } - } - - /// Returns a [`PixelEntry`] - pub fn replace<U: Copy>( - &mut self, - x: u32, - y: u32, - f: impl FnOnce([U; CHANNELS]) -> [U; CHANNELS], - ) -> Option<[U; CHANNELS]> - where - T: AsRef<[U]> + AsMut<[U]>, - { - if x < self.width() && y < self.height() { - let x = unsafe { self.pixel_mut(x, y) }; - let v = *x; - *x = f(v); - Some(v) - } else { - None - } + pub unsafe fn pixel(&self, x: u32, y: u32) -> [u8; CHANNELS] { + let idx = unsafe { self.slice(x, y) }; + let ptr = unsafe { self.buffer.get_unchecked(idx).as_ptr().cast() }; + unsafe { *ptr } } +} +impl<T: std::ops::DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> { /// Return a mutable reference to a pixel at (x, y). /// # Safety /// /// - UB if x, y is out of bounds /// - UB if buffer is too small #[inline] - #[cfg_attr(debug_assertions, track_caller)] - pub unsafe fn pixel_mut<U: Copy>(&mut self, x: u32, y: u32) -> &mut [U; CHANNELS] - where - T: AsMut<[U]> + AsRef<[U]>, - { - debug_assert!(x < self.width()); - debug_assert!(y < self.height()); - - // SAFETY: we have been told x, y is in bounds. - unsafe { self.get_pixel_mut(x, y).unwrap_unchecked() } - } - - /// Returns a mutable reference to a pixel at (x, y), if (x, y) is in bounds. - #[cfg_attr(debug_assertions, track_caller)] - pub fn get_pixel_mut<U>(&mut self, x: u32, y: u32) -> Option<&mut [U; CHANNELS]> - where - T: AsMut<[U]> + AsRef<[U]>, - { - let sl = self.slice(x, y); - ((x < self.width()) & (y < self.height())).then(|| unsafe { - self.buffer_mut() - .as_mut() - .get_unchecked_mut(sl) - .as_mut_array() - .unwrap_unchecked() - }) + pub unsafe fn pixel_mut(&mut self, x: u32, y: u32) -> &mut [u8] { + let idx = unsafe { self.slice(x, y) }; + unsafe { self.buffer.get_unchecked_mut(idx) } } - /// iterator over columns - /// returned iterator returns a iterator for each column - /// - /// ```text - /// ┌ ┐┌ ┐┌ ┐ - /// │1││2││3│ - /// │4││5││6│ - /// │7││8││9│ - /// └ ┘└ ┘└ ┘ - /// ``` - /// - /// ``` - /// # use fimg::Image; - /// let img: Image<&[u8],1> = Image::build(2, 3).buf(&[ - /// 1, 5, - /// 2, 4, - /// 7, 9 - /// ]); - /// assert_eq!( - /// img.cols().map(|x| x.collect::<Vec<_>>()).collect::<Vec<_>>(), - /// [[[1], [2], [7]], [[5], [4], [9]]] - /// ); - /// ``` - #[must_use = "iterators are lazy and do nothing unless consumed"] - pub fn cols<'a, U: Copy + 'a>( - &'a self, - ) -> impl DoubleEndedIterator - + ExactSizeIterator< - Item = impl ExactSizeIterator + DoubleEndedIterator<Item = &'a [U; CHANNELS]>, - > - where - T: AsRef<[U]>, - { - (0..self.width()).map(move |x| (0..self.height()).map(move |y| unsafe { self.pixel(x, y) })) - } - - /// iterator over rows - /// returns a iterator over each row - /// ```text - /// [ 1 2 3 ] - /// [ 4 5 6 ] - /// [ 7 8 9 ] - /// ``` - /// - /// ``` - /// # use fimg::Image; - /// let img: Image<&[u8],1> = Image::build(2, 3).buf(&[ - /// 1, 5, - /// 2, 4, - /// 7, 9 - /// ]); - /// assert_eq!( - /// img.rows().collect::<Vec<_>>(), - /// [[[1], [5]], [[2], [4]], [[7], [9]]] - /// ); - /// ``` - #[must_use = "iterators are lazy and do nothing unless consumed"] - pub fn rows<'a, U: 'a>( - &'a self, - ) -> impl ExactSizeIterator + DoubleEndedIterator<Item = &'a [[U; CHANNELS]]> - where - T: AsRef<[U]>, - { - self.flatten().chunks_exact(self.width() as usize) - } - - /// Itearte the pixels of this image in parse order. - /// use [`Image::chunked`] if you just want the pixels. - pub fn ordered( - &self, - ) -> impl ExactSizeIterator + DoubleEndedIterator<Item = (u32, u32)> + use<T, CHANNELS> { - let w = self.width(); - unsafe { - (0..self.height()) - .flat_map(move |y| (0..w).map(move |x| (x, y))) - .has(self.width() as usize * self.height() as usize) - } - } - - /// Iterate the pixels of this image in serpentine order. - /// - /// # Safety - /// - /// The points are guaranteed to be on the image. - pub fn serpent( - &self, - ) -> impl ExactSizeIterator + Iterator<Item = (u32, u32)> + use<T, CHANNELS> { - let w = self.width(); - unsafe { - (0..self.height() / 2) - .flat_map(move |y| { - std::iter::chain( - (0..w).map(move |x| (x, y * 2)), - (0..w).rev().map(move |x| (x, (y * 2) + 1)), - ) - }) - .take(self.width() as usize * self.height() as usize) - .has(self.width() as usize * self.height() as usize) - } - } - - /// Get the pixels from an iterator. - /// # Safety - /// the points must be on the image. - pub unsafe fn pixels_of<'l, U: Copy + 'l>( - &'l self, - iterator: impl ExactSizeIterator<Item = (u32, u32)> + 'l, - ) -> impl ExactSizeIterator<Item = &'l [U; CHANNELS]> - where - T: AsRef<[U]>, - { - iterator.map(move |(x, y)| unsafe { self.pixel(x, y) }) - } -} - -impl<T: AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> { - /// Bytes of this image. - pub fn bytes(&self) -> &[u8] { - self.buffer.as_ref() - } - - /// Procure a [`ImageCloner`]. - #[must_use = "function does not modify the original image"] - pub fn cloner(&self) -> ImageCloner<'_, CHANNELS> { - ImageCloner::from(self.as_ref()) - } -} - -impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> { #[inline] /// Returns a iterator over every pixel, mutably pub fn chunked_mut(&mut self) -> impl Iterator<Item = &mut [u8; CHANNELS]> { // SAFETY: 0 sized images are not allowed - unsafe { assert_unchecked(self.len() >= CHANNELS) }; - // SAFETY: buffer cannot have half pixels - unsafe { assert_unchecked(self.len() % CHANNELS == 0) }; - self.buffer.as_mut().array_chunks_mut::<CHANNELS>() - } - - #[inline] - /// Flatten the chunks of this image into a mutable slice of slices. - pub fn flatten_mut(&mut self) -> &mut [[u8; CHANNELS]] { + unsafe { assert_unchecked!(self.buffer.len() > CHANNELS) }; // SAFETY: buffer cannot have half pixels - unsafe { self.buffer.as_mut().as_chunks_unchecked_mut::<CHANNELS>() } + unsafe { assert_unchecked!(self.buffer.len() % CHANNELS == 0) }; + self.buffer.array_chunks_mut::<CHANNELS>() } /// Set the pixel at x, y @@ -795,93 +184,74 @@ impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> { /// /// UB if x, y is out of bounds. #[inline] - pub unsafe fn set_pixel(&mut self, x: u32, y: u32, px: &[u8; CHANNELS]) { + pub unsafe fn set_pixel(&mut self, x: u32, y: u32, px: [u8; CHANNELS]) { // SAFETY: Caller says that x, y is in bounds let out = unsafe { self.pixel_mut(x, y) }; // SAFETY: px must be CHANNELS long unsafe { std::ptr::copy_nonoverlapping(px.as_ptr(), out.as_mut_ptr(), CHANNELS) }; } +} - /// Such swap. not actually implemented properly. - pub unsafe fn swap_pixel(&mut self, (x1, y1): (u32, u32), (x2, y2): (u32, u32)) { - unsafe { - let &p2 = self.pixel(x2, y2); - let &p1 = self.pixel(x1, y1); - self.set_pixel(x2, y2, &p1); - self.set_pixel(x1, y1, &p2); - } +pub trait FromRef<const CHANNELS: usize> { + /// Reference the buffer + fn as_ref(&self) -> Image<&[u8], CHANNELS>; +} + +pub trait FromRefMut<const CHANNELS: usize> { + /// Reference the buffer, mutably + fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS>; +} + +impl<const CHANNELS: usize> FromRef<CHANNELS> for Image<&mut [u8], CHANNELS> { + fn as_ref(&self) -> Image<&[u8], CHANNELS> { + Image::new(self.width, self.height, self.buffer) } } -impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> { - /// Copy this ref image - pub fn copy(&mut self) -> Image<&mut [u8], CHANNELS> { - #[allow(clippy::undocumented_unsafe_blocks)] - unsafe { - Image::new(self.width, self.height, self.buffer) - } +impl<const CHANNELS: usize> FromRefMut<CHANNELS> for Image<&mut [u8], CHANNELS> { + fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> { + Image::new(self.width, self.height, self.buffer) + } +} + +impl<const CHANNELS: usize> FromRef<CHANNELS> for Image<Vec<u8>, CHANNELS> { + fn as_ref(&self) -> Image<&[u8], CHANNELS> { + Image::new(self.width, self.height, &self.buffer) + } +} + +impl<const CHANNELS: usize> FromRefMut<CHANNELS> for Image<Vec<u8>, CHANNELS> { + fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> { + Image::new(self.width, self.height, &mut self.buffer) } } impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> { - /// Allocates a new image. If `width` and `height` are constant, try using [`make`]. + /// Allocates a new image /// /// # Panics /// /// if width || height == 0 #[must_use] pub fn alloc(width: u32, height: u32) -> Self { - Self { + Image { width: width.try_into().unwrap(), height: height.try_into().unwrap(), buffer: vec![0; CHANNELS * width as usize * height as usize], } } - - /// Consumes and leaks this image, returning a reference to the image. - #[must_use = "not using the returned reference is a memory leak"] - pub fn leak(self) -> Image<&'static mut [u8], CHANNELS> { - // SAFETY: size unchanged - unsafe { self.mapped(Vec::leak) } - } -} - -impl<const CHANNELS: usize, T: ?Sized> Image<Box<T>, CHANNELS> { - /// Consumes and leaks this image, returning a reference to the image. - #[must_use = "not using the returned reference is a memory leak"] - pub fn leak(self) -> Image<&'static mut T, CHANNELS> { - // SAFETY: size unchanged - unsafe { self.mapped(Box::leak) } - } -} - -#[cfg(feature = "save")] -/// Write a png image. -pub trait WritePng { - /// Write this png image. - fn write(&self, f: &mut impl std::io::Write) -> std::io::Result<()>; } - -/// Read png. -#[cfg(feature = "save")] -pub trait ReadPng -where - Self: Sized, -{ - /// Read a png into an image. - fn read<T: std::io::BufRead + std::io::Seek>(f: &mut T) -> std::io::Result<Self>; -} - -/// helper macro for defining the save() method. macro_rules! save { ($channels:literal == $clr:ident ($clrhuman:literal)) => { - #[cfg(feature = "save")] - impl<T: AsRef<[u8]>> WritePng for Image<T, $channels> { + impl Image<&[u8], $channels> { + #[cfg(feature = "save")] #[doc = "Save this "] #[doc = $clrhuman] #[doc = " image."] - fn write(&self, f: &mut impl std::io::Write) -> std::io::Result<()> { - let mut enc = png::Encoder::new(f, self.width(), self.height()); + pub fn save(&self, f: impl AsRef<std::path::Path>) { + let p = std::fs::File::create(f).unwrap(); + let w = &mut std::io::BufWriter::new(p); + let mut enc = png::Encoder::new(w, self.width(), self.height()); enc.set_color(png::ColorType::$clr); enc.set_depth(png::BitDepth::Eight); enc.set_source_gamma(png::ScaledFloat::new(1.0 / 2.2)); @@ -891,88 +261,13 @@ macro_rules! save { (0.30000, 0.60000), (0.15000, 0.06000), )); - let mut writer = enc.write_header()?; - writer.write_image_data(self.bytes())?; - Ok(()) - } - } - impl<T: AsRef<[u8]>> Image<T, $channels> { - #[cfg(feature = "save")] - #[doc = "Save this "] - #[doc = $clrhuman] - #[doc = " image."] - pub fn save(&self, f: impl AsRef<std::path::Path>) { - self.write(&mut std::io::BufWriter::new( - std::fs::File::create(f).unwrap(), - )) - .unwrap(); + let mut writer = enc.write_header().unwrap(); + writer.write_image_data(self.buffer).unwrap(); } } }; } -macro_rules! read { - ($n:literal) => { - #[cfg(feature = "save")] - impl ReadPng for Image<Box<[u8]>, $n> { - /// Open a PNG image - fn read<T: std::io::BufRead + std::io::Seek>(f: &mut T) -> std::io::Result<Self> { - use png::Transformations as T; - let mut dec = png::Decoder::new(f); - match $n { - 1 | 3 => dec.set_transformations(T::STRIP_16 | T::EXPAND), - 2 | 4 => dec.set_transformations(T::STRIP_16 | T::ALPHA), // alpha implies expand - _ => (), - } - let mut reader = dec.read_info()?; - let mut buf = vec![0; reader.output_buffer_size().unwrap()].into_boxed_slice(); - let info = reader.next_frame(&mut buf)?; - use png::ColorType::*; - macro_rules! n { - ($x:literal) => { - Image::<_, $x>::build(info.width, info.height) - .buf(buf) - .into() - }; - } - Ok(match info.color_type { - Indexed => unreachable!(), // see EXPAND - Grayscale => n![1], - GrayscaleAlpha => n![2], - Rgb => n![3], - Rgba => n![4], - }) - } - } - }; -} -impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> -where - [(); { (CHANNELS <= 4) as usize } - 1]:, -{ - #[cfg(feature = "save")] - /// Open a PNG image - pub fn open(f: impl AsRef<std::path::Path>) -> Self { - let p = std::fs::File::open(f).unwrap(); - let r = &mut std::io::BufReader::new(p); - use core::intrinsics::transmute_unchecked as t; - // SAFETY: ... this is idiotic. - unsafe { - match CHANNELS { - 1 => t(Image::<Box<_>, 1>::read(r).unwrap().unbox()), - 2 => t(Image::<Box<_>, 2>::read(r).unwrap().unbox()), - 3 => t(Image::<Box<_>, 3>::read(r).unwrap().unbox()), - 4 => t(Image::<Box<_>, 4>::read(r).unwrap().unbox()), - _ => unreachable!(), - } - } - } -} -read!(1); -read!(2); -read!(3); -read!(4); - save!(3 == Rgb("RGB")); save!(4 == Rgba("RGBA")); save!(2 == GrayscaleAlpha("YA")); @@ -980,11 +275,14 @@ save!(1 == Grayscale("Y")); #[cfg(test)] macro_rules! img { - [[$($v:literal),+] [$($v2:literal),+]] => { - Image::<Vec<u8>, 1>::build(2,2).buf(vec![$($v,)+ $($v2,)+]) - } + [[$($v:literal),+] [$($v2:literal),+]] => {{ + let from: Image<Vec<u8>, 1> = Image::new( + 2.try_into().unwrap(), + 2.try_into().unwrap(), + vec![$($v,)+ $($v2,)+] + ); + from + }} } #[cfg(test)] use img; - -use crate::slicing::PBounds; |