//! # fimg //! //! Provides fast image operations, such as rotation, flipping, and overlaying. #![feature( slice_swap_unchecked, stmt_expr_attributes, generic_const_exprs, vec_into_raw_parts, slice_as_chunks, unchecked_math, slice_flatten, portable_simd, array_windows, const_option, array_chunks, test )] #![warn( clippy::missing_docs_in_private_items, clippy::multiple_unsafe_ops_per_block, clippy::undocumented_unsafe_blocks, 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 )] #![allow(clippy::zero_prefixed_literal, incomplete_features)] use std::{num::NonZeroU32, slice::SliceIndex}; mod affine; pub mod builder; pub mod cloner; mod drawing; mod overlay; pub mod scale; use cloner::ImageCloner; pub use overlay::{ClonerOverlay, ClonerOverlayAt, Overlay, OverlayAt}; /// like assert!(), but causes undefined behaviour at runtime when the condition is not met. /// /// # Safety /// /// UB if condition is false. 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() } }}; } use assert_unchecked; impl Image<&[u8], 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, 3> { let mut img = Image::<_, 3>::alloc(out_width, out_height); for y in 0..self.height() { // SAFETY: get one row of pixels let from = unsafe { self.buffer .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 = img.at(0, y)..img.at(self.width(), y); // SAFETY: put it in the output let to = unsafe { img.buffer.get_unchecked_mut(first.clone()) }; // copy it in to.copy_from_slice(from); 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) }; } } 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) }; } img } } /// A image with a variable number of channels, and a nonzero size. #[derive(Debug, PartialEq, Eq)] pub struct Image { /// column order 2d slice/vec buffer: T, /// image horizontal size width: NonZeroU32, /// image vertical size height: NonZeroU32, } impl Clone for Image { /// Returns a duplicate of this image. /// ``` /// # use fimg::Image; /// # let i = Image::, 1>::alloc(5,5); /// let new_i = i.clone(); /// ``` /// If you find yourself in the pattern of /// ``` /// # use fimg::Image; /// # let i = Image::, 1>::alloc(5,5); /// let mut i = i.clone(); /// unsafe { i.rot_90() }; /// ``` /// STOP! /// /// Instead use /// ``` /// # use fimg::Image; /// # let i = Image::, 1>::alloc(5,5); /// let i = unsafe { i.cloner().rot_90() }; /// ``` fn clone(&self) -> Self { Self { buffer: self.buffer.clone(), width: self.width, height: self.height, } } } impl Image { #[inline] /// get the height as a [`u32`] pub fn height(&self) -> u32 { self.height.into() } #[inline] /// get the width as a [`u32`] 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 { 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 } } impl Image<&[T], CHANNELS> { /// Allocate a new `Image>` from this imageref. pub fn to_owned(&self) -> Image, CHANNELS> { // SAFETY: we have been constructed already, so must be valid unsafe { Image::new(self.width, self.height, self.buffer.to_vec()) } } } impl Image<&mut [T], CHANNELS> { /// Allocate a new `Image>` from this mutable imageref. pub fn to_owned(&self) -> Image, CHANNELS> { // SAFETY: we have been constructed already, so must be valid unsafe { Image::new(self.width, self.height, self.buffer.to_vec()) } } } impl Copy for Image<&[u8], CHANNELS> {} impl Image<&[u8], CHANNELS> { #[inline] #[must_use] /// Copy this ref image pub const fn copy(&self) -> Self { Self { width: self.width, height: self.height, 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]: Sized, { 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> Image { /// # Safety /// /// the output index is not guranteed to be in bounds #[inline] fn slice(&self, x: u32, y: u32) -> impl SliceIndex<[u8], Output = [u8]> { let index = self.at(x, y); // SAFETY: as long as the buffer isnt wrong, this is 😄 index..unsafe { index.unchecked_add(CHANNELS) } } /// # Safety /// /// the output index is not guranteed to be in bounds #[inline] fn at(&self, x: u32, y: u32) -> usize { debug_assert!(x < self.width(), "x out of bounds"); debug_assert!(y < self.height(), "y out of bounds"); #[allow(clippy::multiple_unsafe_ops_per_block)] // SAFETY: me when uncheck math: 😧 (FIXME) let index = unsafe { let w = self.width(); // y * w + x let tmp = (y as usize).unchecked_mul(w as usize); tmp.unchecked_add(x as usize) }; // SAFETY: 🧐 is unsound? 😖 let index = unsafe { index.unchecked_mul(CHANNELS) }; debug_assert!(self.buffer.len() > index); index } /// Procure a [`ImageCloner`]. #[must_use = "function does not modify the original image"] pub fn cloner(&self) -> ImageCloner<'_, CHANNELS> { ImageCloner::from(self.as_ref()) } /// Reference this image. pub fn as_ref(&self) -> Image<&[u8], CHANNELS> { // SAFETY: we got constructed okay, parameters must be valid unsafe { Image::new(self.width, self.height, &*self.buffer) } } #[inline] /// Returns a iterator over every pixel pub fn chunked(&self) -> impl DoubleEndedIterator { // SAFETY: 0 sized images illegal unsafe { assert_unchecked!(self.buffer.len() > CHANNELS) }; // SAFETY: no half pixels! unsafe { assert_unchecked!(self.buffer.len() % CHANNELS == 0) }; self.buffer.array_chunks::() } #[inline] /// Flatten the chunks of this image into a slice of slices. pub fn flatten(&mut self) -> &[[u8; CHANNELS]] { // SAFETY: buffer cannot have half pixels unsafe { self.buffer.as_chunks_unchecked::() } } /// Return a pixel at (x, y). /// # Safety /// /// - UB if x, y is out of bounds /// - UB if buffer is too small #[inline] pub unsafe fn pixel(&self, x: u32, y: u32) -> [u8; CHANNELS] { // SAFETY: x and y in bounds, slice is okay let ptr = unsafe { self.buffer.get_unchecked(self.slice(x, y)).as_ptr().cast() }; // SAFETY: slice always returns a length of `CHANNELS`, so we `cast()` it for convenience. unsafe { *ptr } } } impl, const CHANNELS: usize> Image { /// 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] pub unsafe fn pixel_mut(&mut self, x: u32, y: u32) -> &mut [u8] { // SAFETY: we have been told x, y is in bounds. let idx = self.slice(x, y); // SAFETY: slice should always return a valid index unsafe { self.buffer.get_unchecked_mut(idx) } } #[inline] /// Returns a iterator over every pixel, mutably pub fn chunked_mut(&mut self) -> impl Iterator { // SAFETY: 0 sized images are not allowed unsafe { assert_unchecked!(self.buffer.len() > CHANNELS) }; // SAFETY: buffer cannot have half pixels unsafe { assert_unchecked!(self.buffer.len() % CHANNELS == 0) }; self.buffer.array_chunks_mut::() } /// Create a mutref to this image pub fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> { // SAFETY: construction went okay unsafe { Image::new(self.width, self.height, &mut self.buffer) } } #[inline] /// Flatten the chunks of this image into a mutable slice of slices. pub fn flatten_mut(&mut self) -> &mut [[u8; CHANNELS]] { // SAFETY: buffer cannot have half pixels unsafe { self.buffer.as_chunks_unchecked_mut::() } } /// # 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" meeans. unsafe fn copy_within(&mut self, src: std::ops::Range, dest: usize) { let std::ops::Range { start, end } = src; debug_assert!( dest <= self.buffer.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.buffer.as_mut_ptr(); std::ptr::copy_nonoverlapping(ptr.add(start), ptr.add(dest), end - start) }; } /// Set the pixel at x, y /// /// # Safety /// /// UB if x, y is out of bounds. #[inline] 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) }; } } impl 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 Image, CHANNELS> { /// Allocates a new image /// /// # Panics /// /// if width || height == 0 #[must_use] pub fn alloc(width: u32, height: u32) -> Self { Self { width: width.try_into().unwrap(), height: height.try_into().unwrap(), buffer: vec![0; CHANNELS * width as usize * height as usize], } } } /// helper macro for defining the save() method. macro_rules! save { ($channels:literal == $clr:ident ($clrhuman:literal)) => { impl> Image { #[cfg(feature = "save")] #[doc = "Save this "] #[doc = $clrhuman] #[doc = " image."] pub fn save(&self, f: impl AsRef) { 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)); enc.set_source_chromaticities(png::SourceChromaticities::new( (0.31270, 0.32900), (0.64000, 0.33000), (0.30000, 0.60000), (0.15000, 0.06000), )); let mut writer = enc.write_header().unwrap(); writer.write_image_data(&self.buffer).unwrap(); } } }; } impl Image, CHANNELS> { #[cfg(feature = "save")] /// Open a PNG image pub fn open(f: impl AsRef) -> Self { let p = std::fs::File::open(f).unwrap(); let r = std::io::BufReader::new(p); let dec = png::Decoder::new(r); let mut reader = dec.read_info().unwrap(); let mut buf = vec![0; reader.output_buffer_size()]; let info = reader.next_frame(&mut buf).unwrap(); use png::ColorType::*; match info.color_type { Indexed | Grayscale => { assert_eq!(CHANNELS, 1, "indexed | grayscale requires one channel") } Rgb => assert_eq!(CHANNELS, 3, "rgb requires three channels"), Rgba => assert_eq!(CHANNELS, 4, "rgba requires four channels"), GrayscaleAlpha => assert_eq!(CHANNELS, 2, "ya requires two channels"), } Self::build(info.width, info.height).buf(buf) } } save!(3 == Rgb("RGB")); save!(4 == Rgba("RGBA")); save!(2 == GrayscaleAlpha("YA")); save!(1 == Grayscale("Y")); #[cfg(test)] macro_rules! img { [[$($v:literal),+] [$($v2:literal),+]] => { Image::, 1>::build(2,2).buf(vec![$($v,)+ $($v2,)+]) } } #[cfg(test)] use img;