Compare commits

..

No commits in common. "b6eb5720c987c44780cbfa2e11644bfcc5f841fe" and "7b39c8e6dc69867a1eb712ef5bd75a61f0db1c64" have entirely different histories.

17 changed files with 121 additions and 350 deletions

2
.gitignore vendored
View file

@ -1,3 +1,3 @@
/target
*.lock
bmp/out.*
bmp/out.bmp

View file

@ -9,16 +9,4 @@ package.repository = "https://codeberg.org/p6nj/bent"
package.keywords = ["databending", "data-bending", "bending", "bend", "art"]
[workspace.dependencies]
fundsp = "0.18.2"
image = "0.25.1"
anyhow = "1.0.86"
bingus = { version = "0.1.0", path = "bingus" }
num-traits = "0.2.19"
dasp_sample = "0.11.0"
rayon = "1.10.0"
dirs = "5.0.1"
rfd = "0.14.1"
derive-new = "0.6.0"
infer = "0.16.0"
indicatif = { version = "0.17.8", features = ["rayon"] }
getset = "0.1.2"

24
LICENSE
View file

@ -1,24 +0,0 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

View file

@ -11,14 +11,7 @@ keywords.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
image = { workspace = true }
fundsp = { workspace = true }
anyhow = { workspace = true }
bingus = { workspace = true }
dasp_sample = { workspace = true }
rayon = { workspace = true }
dirs = { workspace = true }
rfd = { workspace = true }
derive-new = { workspace = true }
infer = { workspace = true }
indicatif = { workspace = true }
anyhow = "1.0.86"
bmp = "0.5.0"
dasp_sample = "0.11.0"
fundsp = { version = "0.18.1", default-features = false, features = ["std"] }

View file

@ -1,131 +1,75 @@
use std::path::PathBuf;
use std::fs::File;
use anyhow::{Context, Result};
use bingus::rawdata::RawData;
use dasp_sample::{Sample, U24};
use derive_new::new;
use dirs::{download_dir, home_dir, picture_dir};
use fundsp::math::uparc;
use image::{ImageFormat, ImageReader, RgbImage};
use indicatif::{ParallelProgressIterator, ProgressStyle};
use rayon::{iter::ParallelIterator, slice::ParallelSlice};
use rfd::FileDialog;
struct Files {
input: PathBuf,
output: PathBuf,
}
#[derive(new)]
struct DataPath {
files: Files,
}
impl Files {
fn try_new(input: PathBuf, output: PathBuf) -> Result<Self> {
Ok(Files {
input: Self::verify_image_file(input, "input")?,
output: Self::verify_image_file(output, "output")?,
})
}
fn verify_image_file(path: PathBuf, label: &'static str) -> Result<PathBuf> {
ImageFormat::from_path(&path).with_context(|| {
format!("your {label} image must have a supported extension from this list:")
+ &ImageFormat::all()
.map(|format| {
format!(
"\n\t{:?} ({})",
format,
format
.extensions_str()
.iter()
.fold(String::new(), |acc, x| acc + &format!(".{x}, "))
.strip_suffix(", ")
.unwrap()
)
})
.reduce(|acc, x| acc + &x)
.unwrap()
})?;
Ok(path)
}
fn prompt() -> Result<Self> {
Files::try_new(
FileDialog::new()
.set_title("Input image")
.set_directory(working_dir())
.add_filter(
"images",
&ImageFormat::all()
.map(ImageFormat::extensions_str)
.flatten()
.collect::<Vec<&'static &'static str>>(),
)
.pick_file()
.context("no input image selected")?,
FileDialog::new()
.set_title("Output image")
.set_directory(working_dir())
.save_file()
.context("no output filename provided")?,
)
}
}
use anyhow::Result;
use bmp::{open, Pixel};
use dasp_sample::{FromSample, Sample, ToSample, U24};
fn main() -> Result<()> {
let dp = DataPath::new(Files::prompt()?);
let img = RawData::<RgbImage>::new(
ImageReader::open(dp.files.input)?
.decode()
.context("can't use this picture")?
.into_rgb8(),
);
let processed = RawData::<RgbImage>::new(
RgbImage::from_raw(
img.width(),
img.height(),
img.par_chunks_exact(3)
.progress_count((img.width() * img.height()).into())
.with_style(ProgressStyle::with_template(
"[{eta}] {bar:40.green/red} {pos}/{len} pixels",
)?)
.map(|px: &[u8]| (px[2] as i32) | ((px[1] as i32) << 8) | ((px[0] as i32) << 16))
.map(U24::new_unchecked)
.map(|x| uparc(x.to_sample()))
.flat_map(|sample: f32| {
let rgb: U24 = sample.to_sample();
let rgo = ((rgb) >> 8.into()) << 8.into();
let roo = ((rgo) >> 16.into()) << 16.into();
[
((roo) >> 16.into()).inner() as u8,
((rgo - roo) >> 8.into()).inner() as u8,
(rgb - rgo).inner() as u8,
]
})
.collect(),
)
.unwrap(),
);
processed.save(dp.files.output)?;
// let bytes: Vec<u8> = (1u8..7).into_iter().collect();
// assert_eq!(
// bytes,
// bytes
// .chunks_exact(3)
// .map(|px: &[u8]| f64::from_ne_bytes(array::from_fn(|i| px[i % px.len()])))
// .flat_map(|px: f64| -> [u8; 3] {
// let px = px.to_ne_bytes();
// array::from_fn(move |i| px[i])
// })
// .collect::<Vec<u8>>()
// );
let mut bmp = open("bmp/bigsample.bmp")?;
for y in 0..bmp.get_height() {
for x in 0..bmp.get_width() {
if x > 100 && x < 300 {
bmp.set_pixel(
x,
y,
sample_to_rgb(rgb_to_sample::<f64>(bmp.get_pixel(x, y))),
);
}
}
}
bmp.to_writer(&mut File::create("bmp/out.bmp")?)?;
Ok(())
}
fn working_dir() -> PathBuf {
picture_dir()
.or(download_dir())
.or(home_dir())
.unwrap_or("/".into())
fn rgb_to_sample<T: Sample + FromSample<U24>>(pix: Pixel) -> T {
(((U24::from(pix.r)) << 16.into()) | (U24::from(pix.g) << 8.into()) | U24::from(pix.b))
.to_sample()
}
fn sample_to_rgb<T: Sample + ToSample<U24>>(sample: T) -> Pixel {
let rgb: U24 = sample.to_sample();
let rgo = ((rgb) >> 8.into()) << 8.into();
let roo = ((rgo) >> 16.into()) << 16.into();
Pixel::new(
((roo) >> 16.into()).inner() as u8,
((rgo - roo) >> 8.into()).inner() as u8,
(rgb - rgo).inner() as u8,
)
}
#[cfg(test)]
mod tests {
use bmp::Pixel;
use dasp_sample::{Sample, I24, I48, U24, U48};
use super::{rgb_to_sample, sample_to_rgb};
#[test]
fn sample_convert_consistency() {
let original = U24::from(42);
assert_eq!(original.clone(), original.to_sample::<f64>().to_sample())
}
#[test]
fn rgb2s2rgb_type_consistency() {
let pix = Pixel::new(45, 18, 143);
assert_eq!(
sample_to_rgb(rgb_to_sample::<f32>(pix)),
sample_to_rgb(rgb_to_sample::<f64>(pix))
);
assert_eq!(
sample_to_rgb(rgb_to_sample::<I24>(pix)),
sample_to_rgb(rgb_to_sample::<I48>(pix))
);
assert_eq!(
sample_to_rgb(rgb_to_sample::<U24>(pix)),
sample_to_rgb(rgb_to_sample::<U48>(pix))
);
}
#[test]
fn rgb2s2rgb() {
let pix = Pixel::new(45, 18, 143);
assert_eq!(pix, (sample_to_rgb(rgb_to_sample::<f64>(pix))));
}
}

View file

@ -10,11 +10,4 @@ keywords.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
[profile.release]
lto = true

View file

@ -1,24 +0,0 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

View file

@ -1,12 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<style>
path {
stroke: blue;
stroke-width: .2;
}
</style>
<path
d="M 0 0 L 100 100 M 100 0 L 0 100 M 1 0 L 99 100 M 0 1 L 100 99 M 2 0 L 98 100 M 0 2 L 100 98 M 3 0 L 97 100 M 0 3 L 100 97 M 4 0 L 96 100 M 0 4 L 100 96 M 5 0 L 95 100 M 0 5 L 100 95 M 6 0 L 94 100 M 0 6 L 100 94 M 7 0 L 93 100 M 0 7 L 100 93 M 8 0 L 92 100 M 0 8 L 100 92 M 9 0 L 91 100 M 0 9 L 100 91 M 10 0 L 90 100 M 0 10 L 100 90 M 11 0 L 89 100 M 0 11 L 100 89 M 12 0 L 88 100 M 0 12 L 100 88 M 13 0 L 87 100 M 0 13 L 100 87 M 14 0 L 86 100 M 0 14 L 100 86 M 15 0 L 85 100 M 0 15 L 100 85 M 16 0 L 84 100 M 0 16 L 100 84 M 17 0 L 83 100 M 0 17 L 100 83 M 18 0 L 82 100 M 0 18 L 100 82 M 19 0 L 81 100 M 0 19 L 100 81 M 20 0 L 80 100 M 0 20 L 100 80 M 21 0 L 79 100 M 0 21 L 100 79 M 22 0 L 78 100 M 0 22 L 100 78 M 23 0 L 77 100 M 0 23 L 100 77 M 24 0 L 76 100 M 0 24 L 100 76 M 25 0 L 75 100 M 0 25 L 100 75 M 26 0 L 74 100 M 0 26 L 100 74 M 27 0 L 73 100 M 0 27 L 100 73 M 28 0 L 72 100 M 0 28 L 100 72 M 29 0 L 71 100 M 0 29 L 100 71 M 30 0 L 70 100 M 0 30 L 100 70 M 31 0 L 69 100 M 0 31 L 100 69 M 32 0 L 68 100 M 0 32 L 100 68 M 33 0 L 67 100 M 0 33 L 100 67 M 34 0 L 66 100 M 0 34 L 100 66 M 35 0 L 65 100 M 0 35 L 100 65 M 36 0 L 64 100 M 0 36 L 100 64 M 37 0 L 63 100 M 0 37 L 100 63 M 38 0 L 62 100 M 0 38 L 100 62 M 39 0 L 61 100 M 0 39 L 100 61 M 40 0 L 60 100 M 0 40 L 100 60 M 41 0 L 59 100 M 0 41 L 100 59 M 42 0 L 58 100 M 0 42 L 100 58 M 43 0 L 57 100 M 0 43 L 100 57 M 44 0 L 56 100 M 0 44 L 100 56 M 45 0 L 55 100 M 0 45 L 100 55 M 46 0 L 54 100 M 0 46 L 100 54 M 47 0 L 53 100 M 0 47 L 100 53 M 48 0 L 52 100 M 0 48 L 100 52 M 49 0 L 51 100 M 0 49 L 100 51 M 50 0 L 50 100 M 0 50 L 100 50 M 51 0 L 49 100 M 0 51 L 100 49 M 52 0 L 48 100 M 0 52 L 100 48 M 53 0 L 47 100 M 0 53 L 100 47 M 54 0 L 46 100 M 0 54 L 100 46 M 55 0 L 45 100 M 0 55 L 100 45 M 56 0 L 44 100 M 0 56 L 100 44 M 57 0 L 43 100 M 0 57 L 100 43 M 58 0 L 42 100 M 0 58 L 100 42 M 59 0 L 41 100 M 0 59 L 100 41 M 60 0 L 40 100 M 0 60 L 100 40 M 61 0 L 39 100 M 0 61 L 100 39 M 62 0 L 38 100 M 0 62 L 100 38 M 63 0 L 37 100 M 0 63 L 100 37 M 64 0 L 36 100 M 0 64 L 100 36 M 65 0 L 35 100 M 0 65 L 100 35 M 66 0 L 34 100 M 0 66 L 100 34 M 67 0 L 33 100 M 0 67 L 100 33 M 68 0 L 32 100 M 0 68 L 100 32 M 69 0 L 31 100 M 0 69 L 100 31 M 70 0 L 30 100 M 0 70 L 100 30 M 71 0 L 29 100 M 0 71 L 100 29 M 72 0 L 28 100 M 0 72 L 100 28 M 73 0 L 27 100 M 0 73 L 100 27 M 74 0 L 26 100 M 0 74 L 100 26 M 75 0 L 25 100 M 0 75 L 100 25 M 76 0 L 24 100 M 0 76 L 100 24 M 77 0 L 23 100 M 0 77 L 100 23 M 78 0 L 22 100 M 0 78 L 100 22 M 79 0 L 21 100 M 0 79 L 100 21 M 80 0 L 20 100 M 0 80 L 100 20 M 81 0 L 19 100 M 0 81 L 100 19 M 82 0 L 18 100 M 0 82 L 100 18 M 83 0 L 17 100 M 0 83 L 100 17 M 84 0 L 16 100 M 0 84 L 100 16 M 85 0 L 15 100 M 0 85 L 100 15 M 86 0 L 14 100 M 0 86 L 100 14 M 87 0 L 13 100 M 0 87 L 100 13 M 88 0 L 12 100 M 0 88 L 100 12 M 89 0 L 11 100 M 0 89 L 100 11 M 90 0 L 10 100 M 0 90 L 100 10 M 91 0 L 9 100 M 0 91 L 100 9 M 92 0 L 8 100 M 0 92 L 100 8 M 93 0 L 7 100 M 0 93 L 100 7 M 94 0 L 6 100 M 0 94 L 100 6 M 95 0 L 5 100 M 0 95 L 100 5 M 96 0 L 4 100 M 0 96 L 100 4 M 97 0 L 3 100 M 0 97 L 100 3 M 98 0 L 2 100 M 0 98 L 100 2 M 99 0 L 1 100 M 0 99 L 100 1"
mask="url(#Mask)" />
</svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -1,15 +0,0 @@
p = lambda x: print(x, end=" ")
def line(coords: tuple[tuple[int]]):
p(f"M {coords[0][0]} {coords[0][1]} L {coords[1][0]} {coords[1][1]}")
n = 100
line(((0, 0), (n, n)))
line(((n, 0), (0, n)))
for i in range(1, n):
line(((i, 0), (n - i, n)))
line(((0, i), (n, n - i)))
print()

View file

@ -1,36 +0,0 @@
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8" />
<title>BENT</title>
<link rel="shortcut icon" href="assets/bent.svg" type="image/svg">
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
</head>
<script type="module">
import init, { greet } from "./pkg/bent.js";
init().then(() => {
document.getElementById("greet-button").onclick = () => {
const name = document.getElementById("name").value;
greet(name);
};
});
</script>
<body>
<header>
<h1>BENT</h1>
</header>
<form onsubmit="return false;">
<p>
<label>Enter your name:</label>
<input type="text" id="name" />
</p>
<button id="greet-button">Greet</button>
<button type="reset">Reset</button>
</form>
</body>
</html>

View file

@ -1,7 +0,0 @@
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
pub fn log(a: &str);
}

View file

@ -1,10 +0,0 @@
use wasm_bindgen::prelude::*;
#[allow(unused_macros)]
#[macro_use]
pub mod macros;
pub mod js;
#[wasm_bindgen]
pub fn greet(name: &str) {
println!("Hello, {name}!");
}

View file

@ -1,27 +0,0 @@
macro_rules! println {
($($t:tt)*) => (crate::js::log(&format_args!($($t)*).to_string()))
}
macro_rules! dbg {
// NOTE: We cannot use `concat!` to make a static string as a format argument
// of `eprintln!` because `file!` could contain a `{` or
// `$val` expression could be a block (`{ .. }`), in which case the `eprintln!`
// will be malformed.
() => {
println!("[{}:{}:{}]", file!(), line!(), column!())
};
($val:expr $(,)?) => {
// Use of `match` here is intentional because it affects the lifetimes
// of temporaries - https://stackoverflow.com/a/48732525/1063961
match $val {
tmp => {
println!("[{}:{}:{}] {} = {:#?}",
file!(), line!(), column!(), stringify!($val), &tmp);
tmp
}
}
};
($($val:expr),+ $(,)?) => {
($(dbg!($val)),+,)
};
}

3
bent/src/main.rs Normal file
View file

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}

View file

@ -1,6 +1,6 @@
[package]
name = "bingus"
version = "0.1.2"
version = "0.1.0"
edition.workspace = true
license.workspace = true
description.workspace = true
@ -10,4 +10,4 @@ keywords.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
derive-new = { workspace = true }
dasp_sample = { workspace = true }

View file

@ -1,2 +1,43 @@
#![forbid(unused_crate_dependencies)]
pub mod rawdata;
use dasp_sample::{FromSample, Sample, U24, U48};
pub trait IntoSample<F>
where
Self: Sized,
{
fn _prepare(self) -> F;
fn into_sample<S: Sample + FromSample<F>>(self) -> S {
Sample::from_sample(self._prepare())
}
}
impl IntoSample<u8> for u8 {
fn _prepare(self) -> u8 {
self
}
}
impl IntoSample<u16> for [u8; 2] {
fn _prepare(self) -> u16 {
((self[0]._prepare() as u16) << 8) | self[1] as u16
}
}
impl IntoSample<U24> for [u8; 3] {
fn _prepare(self) -> U24 {
(U24::from([self[0], self[1]]._prepare()) << 8.into()) | U24::from(self[2])
}
}
impl IntoSample<u32> for [u8; 4] {
fn _prepare(self) -> u32 {
(([self[0], self[1], self[2]]._prepare().inner() as u32) << 8) | self[3] as u32
}
}
impl IntoSample<U48> for [u8; 6] {
fn _prepare(self) -> U48 {
((U48::from([self[0], self[1], self[2], self[3]]._prepare()) << 16u8.into())
| (U48::from(self[4]) << 8u8.into()))
| U48::from(self[5])
}
}

View file

@ -1,36 +0,0 @@
use std::ops::Deref;
use derive_new::new;
pub type Bytes = [u8];
#[derive(new)]
pub struct RawData<D: Deref<Target = Bytes>>(D);
impl<D> From<RawData<D>> for Vec<u8>
where
D: Deref<Target = Bytes>,
{
fn from(value: RawData<D>) -> Self {
value.to_owned()
}
}
impl<D> Clone for RawData<D>
where
D: Clone + Deref<Target = Bytes>,
{
fn clone(&self) -> Self {
Self(self.deref().clone())
}
}
impl<D> Deref for RawData<D>
where
D: Deref<Target = Bytes>,
{
type Target = D;
fn deref(&self) -> &Self::Target {
&self.0
}
}