fast image operations
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs896
1 files changed, 158 insertions, 738 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 447aea0..9de0643 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,221 +1,86 @@
//! # 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,
+ 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,
- 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, incomplete_features)]
+
+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")]
+mod overlay;
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,
-};
-
-trait CopyWithinUnchecked {
- /// # 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;
-}
+pub use overlay::{Overlay, OverlayAt};
-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) }
- }
+/// 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<T: AsRef<[u8]>> Image<T, 3> {
- /// Tile self till it fills a new image of size x, y
+impl Image<&[u8], 3> {
+ /// Repeat 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) };
+ pub unsafe fn repeated(&self, x: u32, y: u32) -> Image<Vec<u8>, 3> {
+ 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
}
}
+/// calculates a column major index, with unchecked math
+#[inline]
+unsafe fn really_unsafe_index(x: u32, y: u32, w: u32) -> usize {
+ // y * w + x
+ // SAFETY: FIXME make safe math
+ let tmp = unsafe { (y as usize).unchecked_mul(w as usize) };
+ // SAFETY: FIXME make safe math
+ unsafe { tmp.unchecked_add(x as usize) }
+}
+
/// A image with a variable number of channels, and a nonzero size.
-#[derive(Debug, PartialEq, Eq, Hash)]
-#[repr(C)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Image<T, const CHANNELS: usize> {
/// column order 2d slice/vec
buffer: T,
@@ -225,53 +90,17 @@ pub struct Image<T, const CHANNELS: usize> {
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 {
- Self {
- buffer: self.buffer.clone(),
- width: self.width,
- height: self.height,
- }
- }
-}
-
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]
@@ -308,59 +137,24 @@ impl<T, const CHANNELS: usize> Image<T, CHANNELS> {
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()) }
+ // SAFETY: we have been constructed already, so must be valid
+ unsafe { Image::new(self.width, self.height, self.buffer.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()) }
+ // SAFETY: we have been constructed already, so must be valid
+ unsafe { Image::new(self.width, self.height, self.buffer.to_vec()) }
}
}
-impl<const CHANNELS: usize> Copy for Image<&[u8], CHANNELS> {}
-
impl<const CHANNELS: usize> Image<&[u8], CHANNELS> {
#[inline]
#[must_use]
@@ -386,7 +180,7 @@ impl<const CHANNELS: usize> Image<&[u8], CHANNELS> {
/// ```
pub const fn make<'a, const WIDTH: u32, const HEIGHT: u32>() -> Image<&'a [u8], CHANNELS>
where
- [(); CHANNELS * WIDTH as usize * HEIGHT as usize]:,
+ [(); CHANNELS * WIDTH as usize * HEIGHT as usize]: Sized,
{
Image {
width: NonZeroU32::new(WIDTH).expect("passed zero width to builder"),
@@ -396,155 +190,32 @@ impl<const CHANNELS: usize> Image<&[u8], CHANNELS> {
}
}
-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
- ///
+impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
/// # 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) }
- }
- /// # 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);
+ 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");
+ // SAFETY: me when uncheck math: 😧
+ let index = unsafe { really_unsafe_index(x, y, self.width()) };
+ // SAFETY: 🧐 is unsound? 😖
+ let index = unsafe { index.unchecked_mul(CHANNELS) };
+ debug_assert!(self.buffer.len() > index);
// SAFETY: as long as the buffer isnt wrong, this is 😄
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 +224,38 @@ 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] {
+ // SAFETY: we have been told x, y is in bounds
+ let idx = unsafe { self.slice(x, y) };
+ // SAFETY: slice always returns a valid index
+ let ptr = unsafe { self.buffer.get_unchecked(idx).as_ptr().cast() };
+ // SAFETY: slice always returns a length of `CHANNELS`, so we `cast()` it for convenience.
+ 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());
-
+ pub unsafe fn pixel_mut(&mut self, x: u32, y: u32) -> &mut [u8] {
// 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()
- })
+ let idx = unsafe { self.slice(x, y) };
+ // SAFETY: slice should always return a valid index
+ 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,25 +264,21 @@ 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);
- }
- }
}
impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
+ /// Downcast the mutable reference
+ 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) }
+ }
+
/// Copy this ref image
pub fn copy(&mut self) -> Image<&mut [u8], CHANNELS> {
#[allow(clippy::undocumented_unsafe_blocks)]
@@ -824,7 +289,27 @@ impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
}
impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
- /// Allocates a new image. If `width` and `height` are constant, try using [`make`].
+ /// Create a reference to this owned image
+ pub fn as_ref(&self) -> Image<&[u8], CHANNELS> {
+ #[allow(clippy::undocumented_unsafe_blocks)]
+ unsafe {
+ Image::new(self.width, self.height, &self.buffer)
+ }
+ }
+}
+
+impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
+ /// Create a mutable reference to this owned image
+ pub fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> {
+ #[allow(clippy::undocumented_unsafe_blocks)]
+ unsafe {
+ Image::new(self.width, self.height, &mut self.buffer)
+ }
+ }
+}
+
+impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
+ /// Allocates a new image
///
/// # Panics
///
@@ -837,51 +322,30 @@ impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
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<Vec<u8>, $channels> {
+ #[cfg(feature = "save")]
+ #[doc = "Save this "]
+ #[doc = $clrhuman]
+ #[doc = " image."]
+ pub fn save(&self, f: impl AsRef<std::path::Path>) {
+ self.as_ref().save(f)
+ }
+ }
+
+ 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,87 +355,35 @@ 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]:,
-{
+impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
#[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!(),
+ 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)
}
}
-read!(1);
-read!(2);
-read!(3);
-read!(4);
save!(3 == Rgb("RGB"));
save!(4 == Rgba("RGBA"));
@@ -987,4 +399,12 @@ macro_rules! img {
#[cfg(test)]
use img;
-use crate::slicing::PBounds;
+#[cfg(test)]
+mod tests {
+ use super::*;
+ #[test]
+ fn repeat() {
+ let x: Image<&[u8], 3> = Image::build(8, 8).buf(include_bytes!("../benches/3_8x8.imgbuf"));
+ unsafe { x.repeated(128, 128) }; // repeat 16 times
+ }
+}