Compare commits

...

5 Commits

21 changed files with 635 additions and 2686 deletions

3
.envrc Normal file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
use flake

108
.gitignore vendored
View File

@ -1,107 +1,3 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Image & data output directory
.direnv/
output/
target/

163
Cargo.lock generated Normal file
View File

@ -0,0 +1,163 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "console"
version = "0.15.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
"windows-sys",
]
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "gegl"
version = "0.0.0"
dependencies = [
"indexmap",
"insta",
]
[[package]]
name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "indexmap"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "insta"
version = "1.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d64600be34b2fcfc267740a243fa7744441bb4947a619ac4e5bb6507f35fbfc"
dependencies = [
"console",
"lazy_static",
"linked-hash-map",
"similar",
"yaml-rust",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "similar"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]

14
Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
# https://doc.rust-lang.org/cargo/reference/manifest.html
[workspace]
members = [
"gegl"
]
resolver = "2"
[workspace.lints.clippy]
missing_docs_in_private_items = "warn"
[workspace.lints.rust]
missing_docs = "warn"
unsafe_code = "forbid"

16
Makefile.toml Normal file
View File

@ -0,0 +1,16 @@
[env]
CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true
# Do a full check of everything.
[tasks.complete-check]
dependencies = [
"clean",
"format",
"check",
"clippy",
"test",
"docs",
"build",
"audit-flow",
"outdated-flow"
]

128
flake.lock Normal file
View File

@ -0,0 +1,128 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1705309234,
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1681202837,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1705883077,
"narHash": "sha256-ByzHHX3KxpU1+V0erFy8jpujTufimh6KaS/Iv3AciHk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5f5210aa20e343b7e35f40c033000db0ef80d7b9",
"type": "github"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1681358109,
"narHash": "sha256-eKyxW4OohHQx9Urxi7TQlFBTDWII+F+x2hklDOQPB50=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "96ba1c52e54e74c3197f4d43026b3f3d92e83ff9",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1705889935,
"narHash": "sha256-77KPBK5e0ACNzIgJDMuptTtEqKvHBxTO3ksqXHHVO+4=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "e36f66bb10b09f5189dc3b1706948eaeb9a1c555",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

17
flake.nix Normal file
View File

@ -0,0 +1,17 @@
{
inputs = {
flake-utils.url = "github:numtide/flake-utils";
rust-overlay.url = "github:oxalica/rust-overlay";
};
outputs = { self, nixpkgs, flake-utils, rust-overlay }:
flake-utils.lib.eachDefaultSystem (system:
let
overlays = [ (import rust-overlay) ];
pkgs = import nixpkgs { inherit system overlays; };
in
{
devShells.default = import ./shell.nix { inherit pkgs; };
}
);
}

23
gegl/Cargo.toml Normal file
View File

@ -0,0 +1,23 @@
# https://doc.rust-lang.org/cargo/reference/manifest.html
[package]
name = "gegl"
description = "GEGL data structure library for Rust."
repository = "https://git.bauke.xyz/driftingnebula/gegl"
license = "AGPL-3.0-or-later"
version = "0.0.0"
authors = ["Bauke <me@bauke.xyz>"]
edition = "2021"
readme = "../README.md"
[lib]
path = "source/lib.rs"
[lints]
workspace = true
[dependencies]
indexmap = "2.1.0"
[dev-dependencies]
insta = "1.34.0"

45
gegl/source/lib.rs Normal file
View File

@ -0,0 +1,45 @@
//! # GEGL
//!
//! > **Ad-hoc GEGL data structure library for Rust.**
mod operations;
pub use operations::*;
pub use indexmap::indexmap;
/// Type alias for a [`indexmap::IndexMap`] with static [`str`] keys and
/// [`String`] values. The reason for [`indexmap`] is to preserve insertion
/// order for simpler testing.
pub type GeglData = indexmap::IndexMap<&'static str, String>;
/// The [`GeglOperation`] trait defines a set of common functions for the
/// individual operations to implement so they can be used with the GEGL CLI.
pub trait GeglOperation: Default + std::fmt::Debug {
/// Some GEGL operations will run infinitely unless you limit the buffer in
/// some way, so all operations must indicate whether or not they should be
/// followed by a crop operation.
fn append_crop_operation(&self) -> bool;
/// Creates the parameters for the graph to be used with the GEGL CLI.
fn graph(&self, include_default_values: bool) -> Vec<String> {
let mut graph = vec![self.name().to_string()];
let defaults = Self::default().values();
for (key, value) in self.values() {
if !include_default_values && defaults.get(key) == Some(&value) {
continue;
}
graph.push(format!("{key}={value}"));
}
graph
}
/// Returns the name of the operation, starting with `gegl:`.
fn name(&self) -> &'static str;
/// Returns the set of configured values for this operation.
fn values(&self) -> GeglData;
}

View File

@ -0,0 +1,45 @@
//! Macro-based [`crate::GeglOperation`] struct generator.
/// A macro to generate a struct that implements [`crate::GeglOperation`].
#[macro_export]
macro_rules! gegl_operation {
(
struct_name: $struct_name:ident,
gegl_name: $gegl_name:expr,
append_crop: $append_crop:expr,
values: ($($key:ident: $key_type:ty, $key_default:expr, $key_doc:expr),*,),
) => {
#[doc = concat!(" The `gegl:", $gegl_name, "` operation.")]
#[derive(Debug)]
pub struct $struct_name {
$(
#[doc = concat!(" ", $key_doc)]
pub $key: $key_type,
)*
}
impl Default for $struct_name {
fn default() -> $struct_name {
$struct_name {
$($key: $key_default,)*
}
}
}
impl $crate::GeglOperation for $struct_name {
fn append_crop_operation(&self) -> bool {
$append_crop
}
fn name(&self) -> &'static str {
concat!("gegl:", $gegl_name)
}
fn values(&self) -> $crate::GeglData {
$crate::indexmap! {
$(stringify!($key) => self.$key.to_string(),)*
}
}
}
};
}

View File

@ -0,0 +1,28 @@
//! All supported GEGL operations.
mod generator;
pub use crate::gegl_operation;
gegl_operation!(
struct_name: Bloom,
gegl_name: "bloom",
append_crop: false,
values: (
limit_exposure: bool, false, "Don't over-expose highlights.",
radius: f64, 10.0, "Glow radius.",
softness: f64, 25.0, "Glow-area edge softness.",
strength: f64, 50.0, "Glow strength.",
threshold: f64, 50.0, "Glow-area brightness threshold.",
),
);
gegl_operation!(
struct_name: Cartoon,
gegl_name: "cartoon",
append_crop: true,
values: (
mask_radius: f64, 7.0, "The mask radius.",
pct_black: f64, 0.2, "The percentage of black.",
),
);

25
gegl/tests/bloom.rs Normal file
View File

@ -0,0 +1,25 @@
use {
gegl::{Bloom, GeglOperation},
insta::assert_debug_snapshot,
};
#[test]
fn test_bloom_graph() {
let mut graphs = vec![];
let op = Bloom {
limit_exposure: true,
radius: 100_f64,
softness: 100_f64,
..Default::default()
};
let default = Bloom::default();
graphs.push(("non-default: exclude defaults", op.graph(false)));
graphs.push(("non-default: include defaults", op.graph(true)));
graphs.push(("default: exclude defaults", default.graph(false)));
graphs.push(("default: include defaults", default.graph(true)));
assert_debug_snapshot!("graphs", graphs);
}

23
gegl/tests/cartoon.rs Normal file
View File

@ -0,0 +1,23 @@
use {
gegl::{Cartoon, GeglOperation},
insta::assert_debug_snapshot,
};
#[test]
fn test_cartoon_graph() {
let mut graphs = vec![];
let op = Cartoon {
mask_radius: 0.1,
..Default::default()
};
let default = Cartoon::default();
graphs.push(("non-default: exclude defaults", op.graph(false)));
graphs.push(("non-default: include defaults", op.graph(true)));
graphs.push(("default: exclude defaults", default.graph(false)));
graphs.push(("default: include defaults", default.graph(true)));
assert_debug_snapshot!("graphs", graphs);
}

View File

@ -0,0 +1,43 @@
---
source: gegl/tests/bloom.rs
expression: graphs
---
[
(
"non-default: exclude defaults",
[
"gegl:bloom",
"limit_exposure=true",
"radius=100",
"softness=100",
],
),
(
"non-default: include defaults",
[
"gegl:bloom",
"limit_exposure=true",
"radius=100",
"softness=100",
"strength=50",
"threshold=50",
],
),
(
"default: exclude defaults",
[
"gegl:bloom",
],
),
(
"default: include defaults",
[
"gegl:bloom",
"limit_exposure=false",
"radius=10",
"softness=25",
"strength=50",
"threshold=50",
],
),
]

View File

@ -0,0 +1,35 @@
---
source: gegl/tests/cartoon.rs
expression: graphs
---
[
(
"non-default: exclude defaults",
[
"gegl:cartoon",
"mask_radius=0.1",
],
),
(
"non-default: include defaults",
[
"gegl:cartoon",
"mask_radius=0.1",
"pct_black=0.2",
],
),
(
"default: exclude defaults",
[
"gegl:cartoon",
],
),
(
"default: include defaults",
[
"gegl:cartoon",
"mask_radius=7",
"pct_black=0.2",
],
),
]

View File

@ -1,28 +0,0 @@
{
"name": "interlinked",
"description": "Generative art with GIMP, GEGL and ImageMagick.",
"license": "AGPL-3.0-or-later",
"version": "1.0.0",
"scripts": {
"start": "ts-node-esm source/interlinked.ts",
"test": "xo"
},
"dependencies": {
"execa": "^6.1.0",
"meow": "^10.1.2"
},
"devDependencies": {
"@types/node": "^18.8.0",
"ts-node": "^10.6.0",
"typescript": "^4.6.2",
"xo": "^0.52.3"
},
"type": "module",
"xo": {
"prettier": true,
"rules": {
"no-await-in-loop": "off"
},
"space": true
}
}

File diff suppressed because it is too large Load Diff

2
rustfmt.toml Normal file
View File

@ -0,0 +1,2 @@
max_width = 80
tab_spaces = 2

3
rustup-toolchain.toml Normal file
View File

@ -0,0 +1,3 @@
[toolchain]
channel = "stable"
components = ["cargo", "clippy", "rustfmt", "rust-src"]

20
shell.nix Normal file
View File

@ -0,0 +1,20 @@
{ pkgs ? import <nixpkgs> { } }:
with pkgs;
let
rustup-toolchain = rust-bin.fromRustupToolchainFile ./rustup-toolchain.toml;
in
mkShell rec {
packages = [
cargo-audit
cargo-edit
cargo-expand
cargo-insta
cargo-make
cargo-outdated
gegl.dev
imagemagick
rustup-toolchain
];
}

View File

@ -1,13 +0,0 @@
{
"compilerOptions": {
"esModuleInterop": true,
"module": "ESNext",
"moduleResolution": "Node",
"outDir": "build",
"strict": true,
"target": "ESNext"
},
"include": [
"source/**/*.ts"
]
}