imagescript 1.3.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +4 -1
- package/README.md +64 -26
- package/THIRD_PARTY_NOTICES.md +74 -0
- package/dist/codecs/crc.d.ts +9 -0
- package/dist/codecs/crc.js +29 -0
- package/dist/codecs/exif.d.ts +11 -0
- package/dist/codecs/exif.js +27 -0
- package/dist/codecs/gif.d.ts +44 -0
- package/dist/codecs/gif.js +401 -0
- package/dist/codecs/jpeg.d.ts +35 -0
- package/dist/codecs/jpeg.js +980 -0
- package/dist/codecs/png.d.ts +44 -0
- package/dist/codecs/png.js +442 -0
- package/dist/codecs/quantize.d.ts +25 -0
- package/dist/codecs/quantize.js +302 -0
- package/dist/codecs/tiff.d.ts +6 -0
- package/dist/codecs/tiff.js +546 -0
- package/dist/codecs/zlib.d.ts +22 -0
- package/dist/codecs/zlib.js +607 -0
- package/dist/frame.d.ts +57 -0
- package/dist/frame.js +65 -0
- package/dist/gif.d.ts +44 -0
- package/dist/gif.js +93 -0
- package/dist/image-type.d.ts +20 -0
- package/dist/image-type.js +49 -0
- package/dist/image.d.ts +521 -0
- package/dist/image.js +1118 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +13 -0
- package/dist/package.json +1 -0
- package/dist/render/font.d.ts +63 -0
- package/dist/render/font.js +857 -0
- package/dist/render/svg.d.ts +11 -0
- package/dist/render/svg.js +1717 -0
- package/dist/render/text.d.ts +61 -0
- package/dist/render/text.js +317 -0
- package/dist/text-layout.d.ts +46 -0
- package/dist/text-layout.js +35 -0
- package/dist/util/blur.d.ts +13 -0
- package/dist/util/blur.js +146 -0
- package/dist/util/mem.d.ts +10 -0
- package/dist/util/mem.js +23 -0
- package/dist/util/resample.d.ts +12 -0
- package/dist/util/resample.js +99 -0
- package/dist/util/utf8.d.ts +5 -0
- package/dist/util/utf8.js +55 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/licenses/Apache-2.0.txt +202 -0
- package/licenses/README.ijg +260 -0
- package/package.json +31 -7
- package/ImageScript.d.ts +0 -235
- package/ImageScript.js +0 -1669
- package/bench/_.mjs +0 -166
- package/bench/all.mjs +0 -4
- package/bench/blur.mjs +0 -59
- package/bench/flip.mjs +0 -63
- package/bench/overlay.mjs +0 -35
- package/bench/package.json +0 -7
- package/bench/readme.md +0 -64
- package/bench/resize.mjs +0 -52
- package/codecs/LICENSE +0 -21
- package/codecs/lib.d.ts +0 -50
- package/codecs/lib.js +0 -6
- package/codecs/lib.mjs +0 -1
- package/codecs/node/bin/arm64-darwin.node +0 -0
- package/codecs/node/bin/arm64-linux.node +0 -0
- package/codecs/node/bin/x64-darwin.node +0 -0
- package/codecs/node/bin/x64-linux.node +0 -0
- package/codecs/node/bin/x64-win32.node +0 -0
- package/codecs/node/index.js +0 -3
- package/codecs/node/index.mjs +0 -6
- package/codecs/package.json +0 -14
- package/codecs/readme.md +0 -38
- package/codecs/tests/gif.js +0 -0
- package/codecs/tests/jpeg.js +0 -0
- package/codecs/tests/png.js +0 -0
- package/codecs/tests/results/gif/1024.nis.gif +0 -0
- package/codecs/tests/results/gif/1024.skyra.gif +0 -0
- package/codecs/tests/results/gif/256.nis.gif +0 -0
- package/codecs/tests/results/gif/256.skyra.gif +0 -0
- package/codecs/tests/results/jpeg/256.jpegjs.jpeg +0 -0
- package/codecs/tests/results/jpeg/256.nis.jpeg +0 -0
- package/codecs/tests/results/jpeg/256.sharp.jpeg +0 -0
- package/codecs/tests/results/jpeg/512.jpegjs.jpeg +0 -0
- package/codecs/tests/results/jpeg/512.nis.jpeg +0 -0
- package/codecs/tests/results/jpeg/512.sharp.jpeg +0 -0
- package/codecs/tests/results/jpeg/64.jpegjs.jpeg +0 -0
- package/codecs/tests/results/jpeg/64.nis.jpeg +0 -0
- package/codecs/tests/results/jpeg/64.sharp.jpeg +0 -0
- package/codecs/tests/results/png/256.jis.png +0 -0
- package/codecs/tests/results/png/256.nis.png +0 -0
- package/codecs/tests/results/png/256.sharp.png +0 -0
- package/codecs/tests/results/png/256.upng.png +0 -0
- package/codecs/tests/results/png/512.jis.png +0 -0
- package/codecs/tests/results/png/512.nis.png +0 -0
- package/codecs/tests/results/png/512.sharp.png +0 -0
- package/codecs/tests/results/png/512.upng.png +0 -0
- package/codecs/tests/results/png/64.jis.png +0 -0
- package/codecs/tests/results/png/64.nis.png +0 -0
- package/codecs/tests/results/png/64.sharp.png +0 -0
- package/codecs/tests/results/png/64.upng.png +0 -0
- package/codecs/tests/webp.js +0 -0
- package/codecs/wasm/bin/codecs.wasm +0 -0
- package/codecs/wasm/bin/simd.wasm +0 -0
- package/codecs/wasm/bundle/browser.js +0 -1
- package/codecs/wasm/index.js +0 -1
- package/codecs/wasm/index.mjs +0 -1
- package/png/README.md +0 -1
- package/png/node.js +0 -1137
- package/png/src/crc.mjs +0 -49
- package/png/src/mem.mjs +0 -24
- package/png/src/png.mjs +0 -254
- package/png/src/zlib.mjs +0 -618
- package/tsconfig.json +0 -21
- package/utils/mem.js +0 -26
- package/v2/codecs/magic.js +0 -25
- package/v2/framebuffer.d.ts +0 -67
- package/v2/framebuffer.js +0 -2352
- package/v2/framebuffer.mjs +0 -126
- package/v2/framebuffer.rs +0 -1264
- package/v2/index.d.ts +0 -84
- package/v2/index.js +0 -261
- package/v2/ops/blur.mjs +0 -303
- package/v2/ops/color.mjs +0 -277
- package/v2/ops/crop.mjs +0 -64
- package/v2/ops/fill.mjs +0 -33
- package/v2/ops/flip.mjs +0 -33
- package/v2/ops/index.mjs +0 -9
- package/v2/ops/iterator.mjs +0 -34
- package/v2/ops/overlay.mjs +0 -63
- package/v2/ops/resize.mjs +0 -166
- package/v2/ops/rotate.mjs +0 -117
- package/v2/util/mem.mjs +0 -24
- package/wasm/any/font.wasm +0 -0
- package/wasm/any/gif.wasm +0 -0
- package/wasm/any/jpeg.wasm +0 -0
- package/wasm/any/png.wasm +0 -0
- package/wasm/any/svg.wasm +0 -0
- package/wasm/any/tiff.wasm +0 -0
- package/wasm/node/font.js +0 -142
- package/wasm/node/gif.js +0 -76
- package/wasm/node/jpeg.js +0 -92
- package/wasm/node/png.js +0 -49
- package/wasm/node/svg.js +0 -56
- package/wasm/node/tiff.js +0 -47
package/v2/framebuffer.rs
DELETED
|
@@ -1,1264 +0,0 @@
|
|
|
1
|
-
#![allow(dead_code)]
|
|
2
|
-
#![warn(clippy::perf)]
|
|
3
|
-
#![feature(decl_macro)]
|
|
4
|
-
#![feature(const_mut_refs)]
|
|
5
|
-
#![feature(unchecked_math)]
|
|
6
|
-
#![warn(clippy::complexity)]
|
|
7
|
-
#![feature(core_intrinsics)]
|
|
8
|
-
#![warn(clippy::correctness)]
|
|
9
|
-
#![allow(non_camel_case_types)]
|
|
10
|
-
#![feature(downcast_unchecked)]
|
|
11
|
-
#![allow(non_upper_case_globals)]
|
|
12
|
-
#![feature(const_slice_from_raw_parts)]
|
|
13
|
-
#![feature(const_fn_floating_point_arithmetic)]
|
|
14
|
-
|
|
15
|
-
macro size_of { ($type:ty) => { std::mem::size_of::<$type>() } }
|
|
16
|
-
#[inline] const fn alloc_len(size: usize) -> usize { return alloc_align(size).size(); }
|
|
17
|
-
#[inline(always)] const unsafe fn unreachable() -> ! { std::hint::unreachable_unchecked(); }
|
|
18
|
-
#[inline] fn alloc(size: usize) -> *mut u8 { unsafe { return std::alloc::alloc(alloc_align(size)); } }
|
|
19
|
-
#[inline] fn free(ptr: *mut u8, size: usize) { unsafe { std::alloc::dealloc(ptr, alloc_align(size)); } }
|
|
20
|
-
#[inline] fn calloc(size: usize) -> *mut u8 { unsafe { return std::alloc::alloc_zeroed(alloc_align(size)); } }
|
|
21
|
-
#[inline] const fn alloc_align(size: usize) -> std::alloc::Layout { return unsafe { std::alloc::Layout::from_size_align_unchecked(size, 16) }; }
|
|
22
|
-
|
|
23
|
-
type fb = framebuffer;
|
|
24
|
-
|
|
25
|
-
pub struct framebuffer {
|
|
26
|
-
pub width: usize,
|
|
27
|
-
pub height: usize,
|
|
28
|
-
ptr: (bool, *mut u8),
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
unsafe impl Send for framebuffer {}
|
|
32
|
-
unsafe impl Sync for framebuffer {}
|
|
33
|
-
|
|
34
|
-
pub trait framebuffer_from<T> {
|
|
35
|
-
fn from(width: usize, height: usize, container: T) -> fb;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
impl Drop for framebuffer {
|
|
39
|
-
fn drop(&mut self) { if self.ptr.0 { free(self.as_mut_ptr(), self.len()); } }
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
impl std::ops::Deref for framebuffer {
|
|
43
|
-
type Target = [u8]; fn deref(&self) -> &Self::Target { return unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) }; }
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
impl std::ops::DerefMut for framebuffer {
|
|
47
|
-
fn deref_mut(&mut self) -> &mut Self::Target { return unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.len()) }; }
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
impl std::ops::IndexMut<(usize, usize)> for framebuffer {
|
|
51
|
-
fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output { return unsafe { &mut *(self.as_mut_ptr::<u32>().add(index.0 + index.1 * self.width) as *mut colors::rgba) }; }
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
impl std::ops::Index<(usize, usize)> for framebuffer {
|
|
55
|
-
type Output = colors::rgba; fn index(&self, index: (usize, usize)) -> &Self::Output { return unsafe { &*(self.as_ptr::<u32>().add(index.0 + index.1 * self.width) as *mut colors::rgba) }; }
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
impl Clone for framebuffer {
|
|
59
|
-
fn clone(&self) -> Self {
|
|
60
|
-
let ptr = alloc(self.len());
|
|
61
|
-
unsafe { self.ptr.1.copy_to_nonoverlapping(ptr, self.len()); }
|
|
62
|
-
return Self { width: self.width, height: self.height, ptr: (true, ptr) };
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
impl<T> framebuffer_from<*mut T> for *mut T { fn from(width: usize, height: usize, container: *mut T) -> fb { return fb { width, height, ptr: (false, container as *mut u8) }; } }
|
|
68
|
-
impl<T> framebuffer_from<&[T]> for &[T] { fn from(width: usize, height: usize, container: &[T]) -> fb { return fb { width, height, ptr: (false, container.as_ptr() as *mut u8) }; } }
|
|
69
|
-
impl<T> framebuffer_from<*const T> for *const T { fn from(width: usize, height: usize, container: *const T) -> fb { return fb { width, height, ptr: (false, container as *mut u8) }; } }
|
|
70
|
-
impl<T> framebuffer_from<&Vec<T>> for &Vec<T> { fn from(width: usize, height: usize, container: &Vec<T>) -> fb { return fb { width, height, ptr: (false, container.as_ptr() as *mut u8) }; } }
|
|
71
|
-
impl<T> framebuffer_from<&mut [T]> for &mut [T] { fn from(width: usize, height: usize, container: &mut [T]) -> fb { return fb { width, height, ptr: (false, container.as_mut_ptr() as *mut u8) }; } }
|
|
72
|
-
impl<T> framebuffer_from<&mut Vec<T>> for &mut Vec<T> { fn from(width: usize, height: usize, container: &mut Vec<T>) -> fb { return fb { width, height, ptr: (false, container.as_mut_ptr() as *mut u8) }; } }
|
|
73
|
-
impl framebuffer_from<colors::rgba> for colors::rgba { fn from(width: usize, height: usize, container: colors::rgba) -> fb { let mut fb = unsafe { framebuffer::new_uninit(width, height) }; ops::fill::color(&mut fb, container); return fb; } }
|
|
74
|
-
impl framebuffer_from<colors::rgb> for colors::rgb { fn from(width: usize, height: usize, container: colors::rgb) -> fb { let mut fb = unsafe { framebuffer::new_uninit(width, height) }; ops::fill::color(&mut fb, container.into()); return fb; } }
|
|
75
|
-
impl<F, T: ops::fill::fill_value> framebuffer_from<F> for F where F: Fn(usize, usize) -> T { fn from(width: usize, height: usize, container: F) -> fb { let mut fb = unsafe { framebuffer::new_uninit(width, height) }; ops::fill::function(&mut fb, container); return fb; } }
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
impl framebuffer {
|
|
79
|
-
pub fn new(width: usize, height: usize) -> Self { return Self { width, height, ptr: (true, calloc(4 * width * height)) }; }
|
|
80
|
-
pub fn from<T: framebuffer_from<T>>(width: usize, height: usize, container: T) -> Self { return T::from(width, height, container); }
|
|
81
|
-
pub unsafe fn new_uninit(width: usize, height: usize) -> Self { return Self { width, height, ptr: (true, alloc(4 * width * height)) }; }
|
|
82
|
-
|
|
83
|
-
pub const fn len(&self) -> usize { return 4 * self.width * self.height; }
|
|
84
|
-
pub const fn as_ptr<T>(&self) -> *const T { return self.ptr.1 as *const T; }
|
|
85
|
-
pub const fn as_mut_ptr<T>(&mut self) -> *mut T { return self.ptr.1 as *mut T; }
|
|
86
|
-
pub const fn as_slice<T>(&self) -> &[T] { return unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len() / size_of!(T)) }; }
|
|
87
|
-
pub const fn as_mut_slice<T>(&mut self) -> &mut [T] { return unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.len() / size_of!(T)) }; }
|
|
88
|
-
pub fn into_vec<T>(mut self) -> Vec<T> { self.ptr.0 = false; return unsafe { Vec::from_raw_parts(self.as_mut_ptr(), self.len() / size_of!(T), alloc_len(self.len()) / size_of!(T)) }; }
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
pub mod colors {
|
|
92
|
-
#[repr(C)] #[derive(Copy, Clone, Debug)] pub struct rgb { pub r: u8, pub g: u8, pub b: u8 }
|
|
93
|
-
#[repr(C)] #[derive(Copy, Clone, Debug)] pub struct rgba { pub r: u8, pub g: u8, pub b: u8, pub a: u8 }
|
|
94
|
-
|
|
95
|
-
impl From<rgba> for rgb { #[inline] fn from(c: rgba) -> rgb { return rgb { r: c.r, g: c.g, b: c.b }; } }
|
|
96
|
-
impl From<rgb> for rgba { #[inline] fn from(c: rgb) -> rgba { return rgba { r: c.r, g: c.g, b: c.b, a: 255 }; } }
|
|
97
|
-
impl From<rgb> for u32 { #[inline] fn from(c: rgb) -> u32 { return c.r as u32 | ((c.g as u32) << 8) | ((c.b as u32) << 16) | (255 << 24); } }
|
|
98
|
-
impl From<rgba> for u32 { #[inline] fn from(c: rgba) -> u32 { return c.r as u32 | ((c.g as u32) << 8) | ((c.b as u32) << 16) | ((c.a as u32) << 24); } }
|
|
99
|
-
impl From<u32> for rgb { #[inline] fn from(c: u32) -> rgb { return rgb { r: (c & 0xFF) as u8, g: ((c >> 8) & 0xFF) as u8, b: ((c >> 16) & 0xFF) as u8 }; } }
|
|
100
|
-
impl From<u32> for rgba { #[inline] fn from(c: u32) -> rgba { return rgba { r: (c & 0xFF) as u8, g: ((c >> 8) & 0xFF) as u8, b: ((c >> 16) & 0xFF) as u8, a: (c >> 24) as u8 }; } }
|
|
101
|
-
|
|
102
|
-
pub fn blend(bg: u32, fg: u32) -> u32 {
|
|
103
|
-
let fa = fg >> 24;
|
|
104
|
-
let alpha = 1 + fa;
|
|
105
|
-
let inv_alpha = 256 - fa;
|
|
106
|
-
let r = (alpha * (fg & 0xff) + inv_alpha * (bg & 0xff)) >> 8;
|
|
107
|
-
let g = (alpha * ((fg >> 8) & 0xff) + inv_alpha * ((bg >> 8) & 0xff)) >> 8;
|
|
108
|
-
let b = (alpha * ((fg >> 16) & 0xff) + inv_alpha * ((bg >> 16) & 0xff)) >> 8;
|
|
109
|
-
return r | ((g & 0xff) << 8) | ((b & 0xff) << 16) | (fa.max(bg >> 24) << 24);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
pub mod ops {
|
|
114
|
-
use super::*;
|
|
115
|
-
|
|
116
|
-
pub mod filter {
|
|
117
|
-
use super::*;
|
|
118
|
-
|
|
119
|
-
pub fn opacity(fb: &mut fb, mut amount: f32) {
|
|
120
|
-
amount = amount.clamp(0.0, 1.0);
|
|
121
|
-
let u8 = unsafe { fb.as_mut_ptr::<u8>().offset(3) };
|
|
122
|
-
|
|
123
|
-
let mut offset = 0;
|
|
124
|
-
let len = fb.len();
|
|
125
|
-
while len > offset {
|
|
126
|
-
use std::intrinsics::{fmul_fast as fm, float_to_int_unchecked as fi};
|
|
127
|
-
unsafe { *u8.add(offset) = fi::<f32, u8>(fm(amount, *u8.add(offset) as f32)); }
|
|
128
|
-
|
|
129
|
-
offset += 4;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
pub fn brightness(fb: &mut fb, amount: f32) {
|
|
134
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
135
|
-
|
|
136
|
-
for o in 0..(fb.len() / 4) {
|
|
137
|
-
unsafe {
|
|
138
|
-
use std::intrinsics::{fmul_fast as fm, float_to_int_unchecked as fi};
|
|
139
|
-
|
|
140
|
-
let c = *u32.add(o);
|
|
141
|
-
let r = fi::<f32, u32>(fm(amount, (c & 0xff) as f32)).min(255);
|
|
142
|
-
let g = fi::<f32, u32>(fm(amount, ((c >> 8) & 0xff) as f32)).min(255);
|
|
143
|
-
let b = fi::<f32, u32>(fm(amount, ((c >> 16) & 0xff) as f32)).min(255);
|
|
144
|
-
|
|
145
|
-
*u32.add(o) = r | (g << 8) | (b << 16) | (c >> 24 << 24);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
pub fn contrast(fb: &mut fb, amount: f32) {
|
|
151
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
152
|
-
let i = 255.0 * (0.5 - (0.5 * amount));
|
|
153
|
-
|
|
154
|
-
for o in 0..(fb.len() / 4) {
|
|
155
|
-
unsafe {
|
|
156
|
-
use std::intrinsics::{fadd_fast as fa, fmul_fast as fm, float_to_int_unchecked as fi};
|
|
157
|
-
|
|
158
|
-
let c = *u32.add(o);
|
|
159
|
-
let r = fi::<f32, u32>(fa(i, fm(amount, (c & 0xff) as f32))).min(255);
|
|
160
|
-
let g = fi::<f32, u32>(fa(i, fm(amount, ((c >> 8) & 0xff) as f32))).min(255);
|
|
161
|
-
let b = fi::<f32, u32>(fa(i, fm(amount, ((c >> 16) & 0xff) as f32))).min(255);
|
|
162
|
-
|
|
163
|
-
*u32.add(o) = r | (g << 8) | (b << 16) | (c >> 24 << 24);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
pub fn saturate(fb: &mut fb, amount: f32) {
|
|
169
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
170
|
-
|
|
171
|
-
let filter: [f32; 9] = [
|
|
172
|
-
0.213 + 0.787 * amount, 0.715 - 0.715 * amount, 0.072 - 0.072 * amount,
|
|
173
|
-
0.213 - 0.213 * amount, 0.715 + 0.285 * amount, 0.072 - 0.072 * amount,
|
|
174
|
-
0.213 - 0.213 * amount, 0.715 - 0.715 * amount, 0.072 + 0.928 * amount,
|
|
175
|
-
];
|
|
176
|
-
|
|
177
|
-
for o in 0..(fb.len() / 4) {
|
|
178
|
-
unsafe {
|
|
179
|
-
use std::intrinsics::{fadd_fast as fa, fmul_fast as fm, float_to_int_unchecked as fi};
|
|
180
|
-
|
|
181
|
-
let c = *u32.add(o);
|
|
182
|
-
let rr = (c & 0xff) as f32;
|
|
183
|
-
let gg = ((c >> 8) & 0xff) as f32;
|
|
184
|
-
let bb = ((c >> 16) & 0xff) as f32;
|
|
185
|
-
let r = fi::<f32, u32>(fa(fm(rr, filter[0]), fa(fm(gg, filter[1]), fm(bb, filter[2])))).clamp(0, 255);
|
|
186
|
-
let g = fi::<f32, u32>(fa(fm(rr, filter[3]), fa(fm(gg, filter[4]), fm(bb, filter[5])))).clamp(0, 255);
|
|
187
|
-
let b = fi::<f32, u32>(fa(fm(rr, filter[6]), fa(fm(gg, filter[7]), fm(bb, filter[8])))).clamp(0, 255);
|
|
188
|
-
|
|
189
|
-
*u32.add(o) = r | (g << 8) | (b << 16) | (c >> 24 << 24);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
pub fn sepia(fb: &mut fb, mut amount: f32) {
|
|
195
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
196
|
-
amount = (1.0 - amount).clamp(0.0, 1.0);
|
|
197
|
-
|
|
198
|
-
let filter: [f32; 9] = [
|
|
199
|
-
0.393 + 0.607 * amount, 0.769 - 0.769 * amount, 0.189 - 0.189 * amount,
|
|
200
|
-
0.349 - 0.349 * amount, 0.686 + 0.314 * amount, 0.168 - 0.168 * amount,
|
|
201
|
-
0.272 - 0.272 * amount, 0.534 - 0.534 * amount, 0.131 + 0.869 * amount,
|
|
202
|
-
];
|
|
203
|
-
|
|
204
|
-
for o in 0..(fb.len() / 4) {
|
|
205
|
-
unsafe {
|
|
206
|
-
use std::intrinsics::{fadd_fast as fa, fmul_fast as fm, float_to_int_unchecked as fi};
|
|
207
|
-
|
|
208
|
-
let c = *u32.add(o);
|
|
209
|
-
let rr = (c & 0xff) as f32;
|
|
210
|
-
let gg = ((c >> 8) & 0xff) as f32;
|
|
211
|
-
let bb = ((c >> 16) & 0xff) as f32;
|
|
212
|
-
let r = fi::<f32, u32>(fa(fm(rr, filter[0]), fa(fm(gg, filter[1]), fm(bb, filter[2])))).clamp(0, 255);
|
|
213
|
-
let g = fi::<f32, u32>(fa(fm(rr, filter[3]), fa(fm(gg, filter[4]), fm(bb, filter[5])))).clamp(0, 255);
|
|
214
|
-
let b = fi::<f32, u32>(fa(fm(rr, filter[6]), fa(fm(gg, filter[7]), fm(bb, filter[8])))).clamp(0, 255);
|
|
215
|
-
|
|
216
|
-
*u32.add(o) = r | (g << 8) | (b << 16) | (c >> 24 << 24);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
pub fn grayscale(fb: &mut fb, mut amount: f32) {
|
|
222
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
223
|
-
amount = (1.0 - amount).clamp(0.0, 1.0);
|
|
224
|
-
|
|
225
|
-
let filter: [f32; 9] = [
|
|
226
|
-
0.2126 + 0.7874 * amount, 0.7152 - 0.7152 * amount, 0.0722 - 0.0722 * amount,
|
|
227
|
-
0.2126 - 0.2126 * amount, 0.7152 + 0.2848 * amount, 0.0722 - 0.0722 * amount,
|
|
228
|
-
0.2126 - 0.2126 * amount, 0.7152 - 0.7152 * amount, 0.0722 + 0.9278 * amount,
|
|
229
|
-
];
|
|
230
|
-
|
|
231
|
-
for o in 0..(fb.len() / 4) {
|
|
232
|
-
unsafe {
|
|
233
|
-
use std::intrinsics::{fadd_fast as fa, fmul_fast as fm, float_to_int_unchecked as fi};
|
|
234
|
-
|
|
235
|
-
let c = *u32.add(o);
|
|
236
|
-
let rr = (c & 0xff) as f32;
|
|
237
|
-
let gg = ((c >> 8) & 0xff) as f32;
|
|
238
|
-
let bb = ((c >> 16) & 0xff) as f32;
|
|
239
|
-
let r = fi::<f32, u32>(fa(fm(rr, filter[0]), fa(fm(gg, filter[1]), fm(bb, filter[2])))).clamp(0, 255);
|
|
240
|
-
let g = fi::<f32, u32>(fa(fm(rr, filter[3]), fa(fm(gg, filter[4]), fm(bb, filter[5])))).clamp(0, 255);
|
|
241
|
-
let b = fi::<f32, u32>(fa(fm(rr, filter[6]), fa(fm(gg, filter[7]), fm(bb, filter[8])))).clamp(0, 255);
|
|
242
|
-
|
|
243
|
-
*u32.add(o) = r | (g << 8) | (b << 16) | (c >> 24 << 24);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
pub fn hue_rotate(fb: &mut fb, deg: f32) {
|
|
249
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
250
|
-
let cos = f32::cos(deg.to_radians());
|
|
251
|
-
let sin = f32::sin(deg.to_radians());
|
|
252
|
-
|
|
253
|
-
let filter: [f32; 9] = [
|
|
254
|
-
0.213 + cos * 0.787 - sin * 0.213, 0.715 - cos * 0.715 - sin * 0.715, 0.072 - cos * 0.072 + sin * 0.928,
|
|
255
|
-
0.213 - cos * 0.213 + sin * 0.143, 0.715 + cos * 0.285 + sin * 0.140, 0.072 - cos * 0.072 - sin * 0.283,
|
|
256
|
-
0.213 - cos * 0.213 - sin * 0.787, 0.715 - cos * 0.715 + sin * 0.715, 0.072 + cos * 0.928 + sin * 0.072,
|
|
257
|
-
];
|
|
258
|
-
|
|
259
|
-
for o in 0..(fb.len() / 4) {
|
|
260
|
-
unsafe {
|
|
261
|
-
use std::intrinsics::{fadd_fast as fa, fmul_fast as fm};
|
|
262
|
-
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] const fn fi<_f, _i>(x: f32) -> u32 { return x as u32; }
|
|
263
|
-
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] use std::intrinsics::{float_to_int_unchecked as fi};
|
|
264
|
-
|
|
265
|
-
let c = *u32.add(o);
|
|
266
|
-
let rr = (c & 0xff) as f32;
|
|
267
|
-
let gg = ((c >> 8) & 0xff) as f32;
|
|
268
|
-
let bb = ((c >> 16) & 0xff) as f32;
|
|
269
|
-
let r = fi::<f32, u32>(fa(fm(rr, filter[0]), fa(fm(gg, filter[1]), fm(bb, filter[2])))).clamp(0, 255);
|
|
270
|
-
let g = fi::<f32, u32>(fa(fm(rr, filter[3]), fa(fm(gg, filter[4]), fm(bb, filter[5])))).clamp(0, 255);
|
|
271
|
-
let b = fi::<f32, u32>(fa(fm(rr, filter[6]), fa(fm(gg, filter[7]), fm(bb, filter[8])))).clamp(0, 255);
|
|
272
|
-
|
|
273
|
-
*u32.add(o) = r | (g << 8) | (b << 16) | (c >> 24 << 24);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
pub fn drop_shadow(fb: &mut fb, x: isize, y: isize, sigma: f32, color: Option<colors::rgba>) {
|
|
279
|
-
let mut old = fb.clone();
|
|
280
|
-
let u32 = old.as_mut_ptr::<u32>();
|
|
281
|
-
ops::blur::gaussian(&mut old, sigma);
|
|
282
|
-
|
|
283
|
-
if color.is_some() {
|
|
284
|
-
unsafe {
|
|
285
|
-
let cc: u32 = color.unwrap_unchecked().into();
|
|
286
|
-
|
|
287
|
-
let ca = cc >> 24;
|
|
288
|
-
let cc = cc & 0xffffff;
|
|
289
|
-
|
|
290
|
-
for o in 0..(fb.len() / 4) {
|
|
291
|
-
let c = *u32.add(o);
|
|
292
|
-
if 0 != (c >> 24) { *u32.add(o) = cc | (c >> 24 << 24) }
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if ca != 255 { ops::filter::opacity(&mut old, 1.0 / 255.0 * ca as f32); }
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
ops::overlay::background(fb, &old, x, y);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
pub fn invert(fb: &mut fb, mut amount: f32) {
|
|
303
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
304
|
-
amount = amount.clamp(0.0, 1.0);
|
|
305
|
-
|
|
306
|
-
if 1.0 == amount {
|
|
307
|
-
for o in 0..(fb.len() / 4) {
|
|
308
|
-
unsafe {
|
|
309
|
-
let c = *u32.add(o);
|
|
310
|
-
*u32.add(o) = !c & 0xffffff | (c >> 24 << 24);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
else {
|
|
316
|
-
let inv = 1.0 - amount;
|
|
317
|
-
|
|
318
|
-
for o in 0..(fb.len() / 4) {
|
|
319
|
-
use std::intrinsics::{fadd_fast as fa, fsub_fast as fs, fmul_fast as fm, float_to_int_unchecked as fi};
|
|
320
|
-
|
|
321
|
-
unsafe {
|
|
322
|
-
let c = *u32.add(o);
|
|
323
|
-
let r = (c & 0xff) as f32;
|
|
324
|
-
let g = ((c >> 8) & 0xff) as f32;
|
|
325
|
-
let b = ((c >> 16) & 0xff) as f32;
|
|
326
|
-
let r = fi::<f32, u32>(fa(fm(r, amount), fm(inv, fs(255.0, r))));
|
|
327
|
-
let g = fi::<f32, u32>(fa(fm(g, amount), fm(inv, fs(255.0, g))));
|
|
328
|
-
let b = fi::<f32, u32>(fa(fm(b, amount), fm(inv, fs(255.0, b))));
|
|
329
|
-
*u32.add(o) = r | ((g & 0xff) << 8) | ((b & 0xff) << 16) | (c >> 24 << 24);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
pub mod crop {
|
|
337
|
-
use super::*;
|
|
338
|
-
use std::ops::Neg;
|
|
339
|
-
|
|
340
|
-
pub fn r#box(fb: &fb, x: isize, y: isize, width: usize, height: usize) -> fb {
|
|
341
|
-
let old = fb;
|
|
342
|
-
let mut fb = fb::new(width, height);
|
|
343
|
-
ops::overlay::replace(&mut fb, old, x.neg(), y.neg());
|
|
344
|
-
|
|
345
|
-
return fb;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
pub mod flip {
|
|
350
|
-
use super::*;
|
|
351
|
-
|
|
352
|
-
pub fn horizontal(fb: &mut fb) {
|
|
353
|
-
let width = fb.width;
|
|
354
|
-
let height = fb.height;
|
|
355
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
356
|
-
for y in 0..height { unsafe { std::slice::from_raw_parts_mut(u32.add(y * width), width).reverse(); } }
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
pub fn vertical(fb: &mut fb) {
|
|
360
|
-
let width = fb.width;
|
|
361
|
-
let height = fb.height;
|
|
362
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
363
|
-
|
|
364
|
-
for y in 0..(height / 2) {
|
|
365
|
-
let yoffset = y * width;
|
|
366
|
-
let yboffset = width * (height - 1 - y);
|
|
367
|
-
for x in 0..width { unsafe { std::ptr::swap(u32.add(x + yoffset), u32.add(x + yboffset)) }; }
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
pub mod fill {
|
|
373
|
-
use super::*;
|
|
374
|
-
|
|
375
|
-
pub trait fill_value { fn value(self) -> u32; }
|
|
376
|
-
impl fill_value for u32 { fn value(self) -> u32 { return self; } }
|
|
377
|
-
impl fill_value for colors::rgb { fn value(self) -> u32 { return self.into(); } }
|
|
378
|
-
impl fill_value for colors::rgba { fn value(self) -> u32 { return self.into(); } }
|
|
379
|
-
|
|
380
|
-
pub fn function<F, T: fill_value>(fb: &mut fb, f: F) where F: Fn(usize, usize) -> T {
|
|
381
|
-
let width = fb.width;
|
|
382
|
-
let height = fb.height;
|
|
383
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
384
|
-
|
|
385
|
-
for y in 0..height {
|
|
386
|
-
let yoffset = y * width;
|
|
387
|
-
for x in 0..width { unsafe { *u32.add(x + yoffset) = f(x, y).value(); } }
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
pub fn color(fb: &mut fb, color: colors::rgba) {
|
|
392
|
-
if color.r == color.g && color.r == color.b && color.r == color.a { unsafe { fb.as_mut_ptr::<u8>().write_bytes(color.r, fb.len()); } }
|
|
393
|
-
|
|
394
|
-
else {
|
|
395
|
-
let width = fb.width;
|
|
396
|
-
let height = fb.height;
|
|
397
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
398
|
-
unsafe { std::slice::from_raw_parts_mut(u32, width).fill(color.into()); }
|
|
399
|
-
for y in 1..height { unsafe { u32.copy_to_nonoverlapping(u32.add(y * width), width); } }
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
pub fn background(fb: &mut fb, color: colors::rgba) {
|
|
404
|
-
let width = fb.width;
|
|
405
|
-
let bg = color.into();
|
|
406
|
-
let height = fb.height;
|
|
407
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
408
|
-
|
|
409
|
-
for y in 0..height {
|
|
410
|
-
let yoffset = y * width;
|
|
411
|
-
|
|
412
|
-
for x in 0..width {
|
|
413
|
-
unsafe {
|
|
414
|
-
let fg = *u32.add(x + yoffset);
|
|
415
|
-
|
|
416
|
-
match (fg >> 24) & 0xff {
|
|
417
|
-
0xff => {},
|
|
418
|
-
0x00 => *u32.add(x + yoffset) = bg,
|
|
419
|
-
_ => *u32.add(x + yoffset) = colors::blend(bg, fg),
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
pub mod rotate {
|
|
428
|
-
use super::*;
|
|
429
|
-
|
|
430
|
-
pub fn rotate180(fb: &mut fb) {
|
|
431
|
-
fb.as_mut_slice::<u32>().reverse();
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
pub fn rotate90(fb: &mut fb) {
|
|
435
|
-
let width = fb.width;
|
|
436
|
-
let height = fb.height;
|
|
437
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
438
|
-
let o32 = alloc(fb.len()) as *mut u32;
|
|
439
|
-
unsafe { u32.copy_to_nonoverlapping(o32, fb.len() / 4); }
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
fb.width = height;
|
|
443
|
-
fb.height = width;
|
|
444
|
-
|
|
445
|
-
for y in 0..height {
|
|
446
|
-
let yoffset = y * width;
|
|
447
|
-
let heighty1 = height - 1 - y;
|
|
448
|
-
for x in 0..width { unsafe { *u32.add(heighty1 + x * height) = *o32.add(x + yoffset); } }
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
free(o32 as *mut u8, fb.len());
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
pub fn rotate270(fb: &mut fb) {
|
|
455
|
-
let width = fb.width;
|
|
456
|
-
let height = fb.height;
|
|
457
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
458
|
-
let o32 = alloc(fb.len()) as *mut u32;
|
|
459
|
-
unsafe { u32.copy_to_nonoverlapping(o32, fb.len() / 4); }
|
|
460
|
-
|
|
461
|
-
fb.width = height;
|
|
462
|
-
fb.height = width;
|
|
463
|
-
|
|
464
|
-
for y in 0..height {
|
|
465
|
-
let yoffset = y * width;
|
|
466
|
-
for x in 0..width { unsafe { *u32.add(y + height * (width - 1 - x)) = *o32.add(x + yoffset); } }
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
free(o32 as *mut u8, fb.len());
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
pub mod overlay {
|
|
474
|
-
use super::*;
|
|
475
|
-
|
|
476
|
-
pub fn replace(fb: &mut fb, fg: &fb, x: isize, y: isize) {
|
|
477
|
-
let f32 = fg.as_ptr::<u32>();
|
|
478
|
-
let b32 = fb.as_mut_ptr::<u32>();
|
|
479
|
-
let (bw, bh) = (fb.width as isize, fb.height as isize);
|
|
480
|
-
let (fw, fh) = (fg.width as isize, fg.height as isize);
|
|
481
|
-
|
|
482
|
-
let top = y.max(0);
|
|
483
|
-
let left = x.max(0);
|
|
484
|
-
let ox = x.min(0).abs();
|
|
485
|
-
let oy = y.min(0).abs();
|
|
486
|
-
let width = bw.min(x + fw) - left;
|
|
487
|
-
let height = bh.min(y + fh) - top;
|
|
488
|
-
if 0 >= width || 0 >= height { return; }
|
|
489
|
-
|
|
490
|
-
for yy in 0..height {
|
|
491
|
-
let yyoffset = ox + fw * (yy + oy);
|
|
492
|
-
let yoffset = left + bw * (yy + top);
|
|
493
|
-
unsafe { b32.offset(yoffset).copy_from(f32.offset(yyoffset), width as usize); }
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
pub fn blend(fb: &mut fb, fg: &fb, x: isize, y: isize) {
|
|
498
|
-
let f32 = fg.as_ptr::<u32>();
|
|
499
|
-
let b32 = fb.as_mut_ptr::<u32>();
|
|
500
|
-
let (bw, bh) = (fb.width as isize, fb.height as isize);
|
|
501
|
-
let (fw, fh) = (fg.width as isize, fg.height as isize);
|
|
502
|
-
|
|
503
|
-
let top = y.max(0);
|
|
504
|
-
let left = x.max(0);
|
|
505
|
-
let ox = x.min(0).abs();
|
|
506
|
-
let oy = y.min(0).abs();
|
|
507
|
-
let width = bw.min(x + fw) - left;
|
|
508
|
-
let height = bh.min(y + fh) - top;
|
|
509
|
-
if 0 >= width || 0 >= height { return; }
|
|
510
|
-
|
|
511
|
-
for yy in 0..height {
|
|
512
|
-
let yyoffset = ox + fw * (yy + oy);
|
|
513
|
-
let yoffset = left + bw * (yy + top);
|
|
514
|
-
|
|
515
|
-
for xx in 0..width {
|
|
516
|
-
unsafe {
|
|
517
|
-
let fg = *f32.offset(xx + yyoffset);
|
|
518
|
-
|
|
519
|
-
match fg >> 24 {
|
|
520
|
-
0x00 => {},
|
|
521
|
-
0xff => *b32.offset(xx + yoffset) = fg,
|
|
522
|
-
|
|
523
|
-
fa => {
|
|
524
|
-
let alpha = 1 + fa;
|
|
525
|
-
let inv_alpha = 256 - fa;
|
|
526
|
-
let bg = *b32.offset(xx + yoffset);
|
|
527
|
-
let r = (alpha * (fg & 0xff) + inv_alpha * (bg & 0xff)) >> 8;
|
|
528
|
-
let g = (alpha * ((fg >> 8) & 0xff) + inv_alpha * ((bg >> 8) & 0xff)) >> 8;
|
|
529
|
-
let b = (alpha * ((fg >> 16) & 0xff) + inv_alpha * ((bg >> 16) & 0xff)) >> 8;
|
|
530
|
-
*b32.offset(xx + yoffset) = r | ((g & 0xff) << 8) | ((b & 0xff) << 16) | (fa.max(bg >> 24) << 24);
|
|
531
|
-
},
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
pub fn background(fb: &mut fb, bg: &fb, x: isize, y: isize) {
|
|
539
|
-
let bb32 = bg.as_ptr::<u32>();
|
|
540
|
-
let b32 = fb.as_mut_ptr::<u32>();
|
|
541
|
-
let (bw, bh) = (fb.width as isize, fb.height as isize);
|
|
542
|
-
let (fw, fh) = (bg.width as isize, bg.height as isize);
|
|
543
|
-
|
|
544
|
-
let top = y.max(0);
|
|
545
|
-
let left = x.max(0);
|
|
546
|
-
let ox = x.min(0).abs();
|
|
547
|
-
let oy = y.min(0).abs();
|
|
548
|
-
let width = bw.min(x + fw) - left;
|
|
549
|
-
let height = bh.min(y + fh) - top;
|
|
550
|
-
if 0 >= width || 0 >= height { return; }
|
|
551
|
-
|
|
552
|
-
for yy in 0..height {
|
|
553
|
-
let yyoffset = ox + fw * (yy + oy);
|
|
554
|
-
let yoffset = left + bw * (yy + top);
|
|
555
|
-
|
|
556
|
-
for xx in 0..width {
|
|
557
|
-
unsafe {
|
|
558
|
-
let fg = *b32.offset(xx + yoffset);
|
|
559
|
-
|
|
560
|
-
match fg >> 24 {
|
|
561
|
-
0xff => {},
|
|
562
|
-
0x00 => *b32.offset(xx + yoffset) = *bb32.offset(xx + yyoffset),
|
|
563
|
-
|
|
564
|
-
fa => {
|
|
565
|
-
let alpha = 1 + fa;
|
|
566
|
-
let inv_alpha = 256 - fa;
|
|
567
|
-
let bg = *bb32.offset(xx + yyoffset);
|
|
568
|
-
let r = (alpha * (fg & 0xff) + inv_alpha * (bg & 0xff)) >> 8;
|
|
569
|
-
let g = (alpha * ((fg >> 8) & 0xff) + inv_alpha * ((bg >> 8) & 0xff)) >> 8;
|
|
570
|
-
let b = (alpha * ((fg >> 16) & 0xff) + inv_alpha * ((bg >> 16) & 0xff)) >> 8;
|
|
571
|
-
*b32.offset(xx + yoffset) = r | ((g & 0xff) << 8) | ((b & 0xff) << 16) | (fa.max(bg >> 24) << 24);
|
|
572
|
-
},
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
pub mod resize {
|
|
581
|
-
use super::*;
|
|
582
|
-
|
|
583
|
-
const fn lerp(a: u8, b: u8, t: f64) -> u8 {
|
|
584
|
-
return ((t * b as f64) + a as f64 * (1.0 - t)) as u8;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
fn clamped(x: usize, y: usize, width: usize, height: usize) -> usize {
|
|
588
|
-
return 4 * (x.clamp(0, width - 1) + width * y.clamp(0, height - 1));
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
const fn hermite(a: f64, b: f64, c: f64, d: f64, t: f64) -> f64 {
|
|
592
|
-
let cc = (c / 2.0) + (a / -2.0);
|
|
593
|
-
let bb = a + (c * 2.0) - (d / 2.0) - (b * 2.5);
|
|
594
|
-
let aa = (d / 2.0) + (a / -2.0) + (b * 1.5) - (c * 1.5);
|
|
595
|
-
|
|
596
|
-
let t2 = t * t;
|
|
597
|
-
return b + (t * cc) + (bb * t2) + (t * aa * t2);
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
pub fn nearest(fb: &fb, width: usize, height: usize) -> fb {
|
|
601
|
-
let owidth = fb.width;
|
|
602
|
-
let oheight = fb.height;
|
|
603
|
-
let o32 = fb.as_ptr::<u32>();
|
|
604
|
-
let mut fb = unsafe { framebuffer::new_uninit(width, height) };
|
|
605
|
-
|
|
606
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
607
|
-
let xw = 1.0 / width as f64 * owidth as f64;
|
|
608
|
-
let yw = 1.0 / height as f64 * oheight as f64;
|
|
609
|
-
|
|
610
|
-
for y in 0..height {
|
|
611
|
-
let yoffset = y * width;
|
|
612
|
-
let yyoffset = owidth * (yw * y as f64) as usize;
|
|
613
|
-
for x in 0..width { unsafe { *u32.add(x + yoffset) = *o32.add(yyoffset + (xw * x as f64) as usize); } };
|
|
614
|
-
};
|
|
615
|
-
|
|
616
|
-
return fb;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
pub unsafe fn linear(fb: &fb, width: usize, height: usize) -> fb {
|
|
620
|
-
let owidth = fb.width;
|
|
621
|
-
let oheight = fb.height;
|
|
622
|
-
let o8 = fb.as_ptr::<u8>();
|
|
623
|
-
let mut fb = framebuffer::new(width, height);
|
|
624
|
-
|
|
625
|
-
let mut offset = 0;
|
|
626
|
-
let u8 = fb.as_mut_ptr::<u8>();
|
|
627
|
-
let width1 = 1.0 / (width - 1) as f64;
|
|
628
|
-
let height1 = 1.0 / (height - 1) as f64;
|
|
629
|
-
|
|
630
|
-
for y in 0..height {
|
|
631
|
-
let yy = oheight as f64 * (y as f64 * height1) - 0.5;
|
|
632
|
-
|
|
633
|
-
let yyi = yy as usize;
|
|
634
|
-
let ty = yy - yyi as f64;
|
|
635
|
-
|
|
636
|
-
for x in 0..width {
|
|
637
|
-
let xx = owidth as f64 * (x as f64 * width1) - 0.5;
|
|
638
|
-
|
|
639
|
-
let xxi = xx as usize;
|
|
640
|
-
let tx = xx - xxi as f64;
|
|
641
|
-
|
|
642
|
-
let s0 = clamped(xxi, yyi, owidth, oheight);
|
|
643
|
-
let s1 = clamped(1 + xxi, yyi, owidth, oheight);
|
|
644
|
-
let s2 = clamped(xxi, 1 + yyi, owidth, oheight);
|
|
645
|
-
let s3 = clamped(1 + xxi, 1 + yyi, owidth, oheight);
|
|
646
|
-
|
|
647
|
-
// unsafe {
|
|
648
|
-
*u8.offset(offset) = lerp(lerp(*o8.add(s0), *o8.add(s2), tx), lerp(*o8.add(s1), *o8.add(s3), tx), ty);
|
|
649
|
-
*u8.offset(1 + offset) = lerp(lerp(*o8.add(1 + s0), *o8.add(1 + s2), tx), lerp(*o8.add(1 + s1), *o8.add(1 + s3), tx), ty);
|
|
650
|
-
*u8.offset(2 + offset) = lerp(lerp(*o8.add(2 + s0), *o8.add(2 + s2), tx), lerp(*o8.add(2 + s1), *o8.add(2 + s3), tx), ty);
|
|
651
|
-
*u8.offset(3 + offset) = lerp(lerp(*o8.add(3 + s0), *o8.add(3 + s2), tx), lerp(*o8.add(3 + s1), *o8.add(3 + s3), tx), ty);
|
|
652
|
-
// }
|
|
653
|
-
|
|
654
|
-
offset += 4;
|
|
655
|
-
};
|
|
656
|
-
};
|
|
657
|
-
|
|
658
|
-
return fb;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
pub unsafe fn cubic(fb: &fb, width: usize, height: usize) -> fb {
|
|
662
|
-
let owidth = fb.width;
|
|
663
|
-
let oheight = fb.height;
|
|
664
|
-
let o8 = fb.as_ptr::<u8>();
|
|
665
|
-
let mut fb = framebuffer::new(width, height);
|
|
666
|
-
|
|
667
|
-
let mut offset = 0;
|
|
668
|
-
let u8 = fb.as_mut_ptr::<u8>();
|
|
669
|
-
let width1 = 1.0 / (width - 1) as f64;
|
|
670
|
-
let height1 = 1.0 / (height - 1) as f64;
|
|
671
|
-
|
|
672
|
-
for y in 0..height {
|
|
673
|
-
let yy = oheight as f64 * (y as f64 * height1) - 0.5;
|
|
674
|
-
|
|
675
|
-
let yyi = yy as usize;
|
|
676
|
-
let ty = yy - yyi as f64;
|
|
677
|
-
|
|
678
|
-
for x in 0..width {
|
|
679
|
-
let xx = owidth as f64 * (x as f64 * width1) - 0.5;
|
|
680
|
-
|
|
681
|
-
let xxi = xx as usize;
|
|
682
|
-
let tx = xx - xxi as f64;
|
|
683
|
-
|
|
684
|
-
let s0 = clamped(xxi - 1, yyi - 1, owidth, oheight);
|
|
685
|
-
|
|
686
|
-
let s1 = clamped(xxi, yyi - 1, owidth, oheight);
|
|
687
|
-
let s2 = clamped(1 + xxi, yyi - 1, owidth, oheight);
|
|
688
|
-
let s3 = clamped(2 + xxi, yyi - 1, owidth, oheight);
|
|
689
|
-
|
|
690
|
-
let s4 = clamped(xxi - 1, yyi, owidth, oheight);
|
|
691
|
-
|
|
692
|
-
let s5 = clamped(xxi, yyi, owidth, oheight);
|
|
693
|
-
let s6 = clamped(1 + xxi, yyi, owidth, oheight);
|
|
694
|
-
let s7 = clamped(2 + xxi, yyi, owidth, oheight);
|
|
695
|
-
|
|
696
|
-
let s8 = clamped(xxi - 1, 1 + yyi, owidth, oheight);
|
|
697
|
-
|
|
698
|
-
let s9 = clamped(xxi, 1 + yyi, owidth, oheight);
|
|
699
|
-
let s10 = clamped(1 + xxi, 1 + yyi, owidth, oheight);
|
|
700
|
-
let s11 = clamped(2 + xxi, 1 + yyi, owidth, oheight);
|
|
701
|
-
|
|
702
|
-
let s12 = clamped(xxi - 1, 2 + yyi, owidth, oheight);
|
|
703
|
-
|
|
704
|
-
let s13 = clamped(xxi, 2 + yyi, owidth, oheight);
|
|
705
|
-
let s14 = clamped(1 + xxi, 2 + yyi, owidth, oheight);
|
|
706
|
-
let s15 = clamped(2 + xxi, 2 + yyi, owidth, oheight);
|
|
707
|
-
|
|
708
|
-
// unsafe {
|
|
709
|
-
let c0 = hermite(*o8.add(s0) as f64, *o8.add(s1) as f64, *o8.add(s2) as f64, *o8.add(s3) as f64, tx);
|
|
710
|
-
let c00 = hermite(*o8.add(1 + s0) as f64, *o8.add(1 + s1) as f64, *o8.add(1 + s2) as f64, *o8.add(1 + s3) as f64, tx);
|
|
711
|
-
let c000 = hermite(*o8.add(2 + s0) as f64, *o8.add(2 + s1) as f64, *o8.add(2 + s2) as f64, *o8.add(2 + s3) as f64, tx);
|
|
712
|
-
let c0000 = hermite(*o8.add(3 + s0) as f64, *o8.add(3 + s1) as f64, *o8.add(3 + s2) as f64, *o8.add(3 + s3) as f64, tx);
|
|
713
|
-
|
|
714
|
-
let c1 = hermite(*o8.add(s4) as f64, *o8.add(s5) as f64, *o8.add(s6) as f64, *o8.add(s7) as f64, tx);
|
|
715
|
-
let c11 = hermite(*o8.add(1 + s4) as f64, *o8.add(1 + s5) as f64, *o8.add(1 + s6) as f64, *o8.add(1 + s7) as f64, tx);
|
|
716
|
-
let c111 = hermite(*o8.add(2 + s4) as f64, *o8.add(2 + s5) as f64, *o8.add(2 + s6) as f64, *o8.add(2 + s7) as f64, tx);
|
|
717
|
-
let c1111 = hermite(*o8.add(3 + s4) as f64, *o8.add(3 + s5) as f64, *o8.add(3 + s6) as f64, *o8.add(3 + s7) as f64, tx);
|
|
718
|
-
|
|
719
|
-
let c2 = hermite(*o8.add(s8) as f64, *o8.add(s9) as f64, *o8.add(s10) as f64, *o8.add(s11) as f64, tx);
|
|
720
|
-
let c22 = hermite(*o8.add(1 + s8) as f64, *o8.add(1 + s9) as f64, *o8.add(1 + s10) as f64, *o8.add(1 + s11) as f64, tx);
|
|
721
|
-
let c222 = hermite(*o8.add(2 + s8) as f64, *o8.add(2 + s9) as f64, *o8.add(2 + s10) as f64, *o8.add(2 + s11) as f64, tx);
|
|
722
|
-
let c2222 = hermite(*o8.add(3 + s8) as f64, *o8.add(3 + s9) as f64, *o8.add(3 + s10) as f64, *o8.add(3 + s11) as f64, tx);
|
|
723
|
-
|
|
724
|
-
let c3 = hermite(*o8.add(s12) as f64, *o8.add(s13) as f64, *o8.add(s14) as f64, *o8.add(s15) as f64, tx);
|
|
725
|
-
let c33 = hermite(*o8.add(1 + s12) as f64, *o8.add(1 + s13) as f64, *o8.add(1 + s14) as f64, *o8.add(1 + s15) as f64, tx);
|
|
726
|
-
let c333 = hermite(*o8.add(2 + s12) as f64, *o8.add(2 + s13) as f64, *o8.add(2 + s14) as f64, *o8.add(2 + s15) as f64, tx);
|
|
727
|
-
let c3333 = hermite(*o8.add(3 + s12) as f64, *o8.add(3 + s13) as f64, *o8.add(3 + s14) as f64, *o8.add(3 + s15) as f64, tx);
|
|
728
|
-
|
|
729
|
-
*u8.offset(offset) = hermite(c0, c1, c2, c3, ty) as u8;
|
|
730
|
-
*u8.offset(1 + offset) = hermite(c00, c11, c22, c33, ty) as u8;
|
|
731
|
-
*u8.offset(2 + offset) = hermite(c000, c111, c222, c333, ty) as u8;
|
|
732
|
-
*u8.offset(3 + offset) = hermite(c0000, c1111, c2222, c3333, ty) as u8;
|
|
733
|
-
// }
|
|
734
|
-
|
|
735
|
-
offset += 4;
|
|
736
|
-
};
|
|
737
|
-
};
|
|
738
|
-
|
|
739
|
-
return fb;
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
pub mod blur {
|
|
744
|
-
use super::*;
|
|
745
|
-
|
|
746
|
-
pub fn gaussian(fb: &mut fb, sigma: f32) {
|
|
747
|
-
if 0.0 == sigma { return; }
|
|
748
|
-
|
|
749
|
-
let cof = {
|
|
750
|
-
let a = (0.726f32).powi(2).exp() / sigma;
|
|
751
|
-
|
|
752
|
-
let l = (-a).exp();
|
|
753
|
-
let c = (-a * 2.0).exp();
|
|
754
|
-
let k = (1.0 - l).powi(2) / (1.0 - c + a * l * 2.0);
|
|
755
|
-
|
|
756
|
-
let a3 = c * -k;
|
|
757
|
-
let b1 = l * 2.0;
|
|
758
|
-
let a1 = l * k * (a - 1.0);
|
|
759
|
-
let a2 = l * k * (a + 1.0);
|
|
760
|
-
(k, a1, a2, a3, b1, -c, (k + a1) / (c - b1 + 1.0), (a2 + a3) / (c - b1 + 1.0))
|
|
761
|
-
};
|
|
762
|
-
|
|
763
|
-
let width = fb.width;
|
|
764
|
-
let height = fb.height;
|
|
765
|
-
|
|
766
|
-
unsafe {
|
|
767
|
-
let o8 = alloc(fb.len());
|
|
768
|
-
let u8 = fb.as_mut_ptr::<u8>();
|
|
769
|
-
let f32 = alloc(4 * 4 * width.max(height)) as *mut f32;
|
|
770
|
-
|
|
771
|
-
u8.copy_to(o8, fb.len());
|
|
772
|
-
gc(o8, u8, f32, width, height, cof);
|
|
773
|
-
gc(u8, o8, f32, height, width, cof);
|
|
774
|
-
|
|
775
|
-
free(o8, fb.len());
|
|
776
|
-
free(f32 as *mut u8, 4 * 4 * width.max(height));
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
unsafe fn gc(u8: *mut u8, o8: *mut u8, f32: *mut f32, width: usize, height: usize, (k, a1, a2, a3, b1, b2, lc, rc): (f32, f32, f32, f32, f32, f32, f32, f32)) {
|
|
781
|
-
use std::intrinsics::{fmul_fast as fm, fadd_fast as fa, float_to_int_unchecked as fi};
|
|
782
|
-
|
|
783
|
-
let width4 = 4 * width;
|
|
784
|
-
let height4 = 4 * height;
|
|
785
|
-
let hw1 = height * (width - 1);
|
|
786
|
-
|
|
787
|
-
for y in 0..height {
|
|
788
|
-
let mut toffset = 0;
|
|
789
|
-
let mut ooffset = y * width4;
|
|
790
|
-
let mut offset = 4 * (y + hw1);
|
|
791
|
-
|
|
792
|
-
let (mut por, mut pog, mut pob, mut poa) = (*o8.add(ooffset) as f32, *o8.add(1 + ooffset) as f32, *o8.add(2 + ooffset) as f32, *o8.add(3 + ooffset) as f32);
|
|
793
|
-
let (mut fur, mut fug, mut fub, mut fua) = (fm(lc, por), fm(lc, pog), fm(lc, pob), fm(lc, poa)); let (mut tur, mut tug, mut tub, mut tua) = (fur, fug, fub, fua);
|
|
794
|
-
|
|
795
|
-
for _ in 0..width {
|
|
796
|
-
let (cor, cog, cob, coa) = (*o8.add(ooffset) as f32, *o8.add(1 + ooffset) as f32, *o8.add(2 + ooffset) as f32, *o8.add(3 + ooffset) as f32);
|
|
797
|
-
let (cur, cug, cub, cua) = (fm(k, cor) + fm(a1, por) + fm(b1, fur) + fm(b2, tur), fm(k, cog) + fm(a1, pog) + fm(b1, fug) + fm(b2, tug), fm(k, cob) + fm(a1, pob) + fm(b1, fub) + fm(b2, tub), fm(k, coa) + fm(a1, poa) + fm(b1, fua) + fm(b2, tua));
|
|
798
|
-
|
|
799
|
-
(tur, tug, tub, tua) = (fur, fug, fub, fua);
|
|
800
|
-
(fur, fug, fub, fua) = (cur, cug, cub, cua);
|
|
801
|
-
(por, pog, pob, poa) = (cor, cog, cob, coa);
|
|
802
|
-
|
|
803
|
-
*f32.offset(toffset) = fur;
|
|
804
|
-
*f32.offset(1 + toffset) = fug;
|
|
805
|
-
*f32.offset(2 + toffset) = fub;
|
|
806
|
-
*f32.offset(3 + toffset) = fua;
|
|
807
|
-
|
|
808
|
-
ooffset += 4;
|
|
809
|
-
toffset += 4;
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
ooffset -= 4;
|
|
813
|
-
toffset -= 4;
|
|
814
|
-
|
|
815
|
-
por = *o8.add(ooffset) as f32;
|
|
816
|
-
pog = *o8.add(1 + ooffset) as f32;
|
|
817
|
-
pob = *o8.add(2 + ooffset) as f32;
|
|
818
|
-
poa = *o8.add(3 + ooffset) as f32;
|
|
819
|
-
(tur, tug, tub, tua) = (fm(rc, por), fm(rc, pog), fm(rc, pob), fm(rc, poa));
|
|
820
|
-
|
|
821
|
-
(fur, fug, fub, fua) = (tur, tug, tub, tua);
|
|
822
|
-
let (mut cor, mut cog, mut cob, mut coa) = (por, pog, pob, poa);
|
|
823
|
-
|
|
824
|
-
for _ in 0..width {
|
|
825
|
-
let (cur, cug, cub, cua) = (fm(a2, cor) + fm(a3, por) + fm(b1, fur) + fm(b2, tur), fm(a2, cog) + fm(a3, pog) + fm(b1, fug) + fm(b2, tug), fm(a2, cob) + fm(a3, pob) + fm(b1, fub) + fm(b2, tub), fm(a2, coa) + fm(a3, poa) + fm(b1, fua) + fm(b2, tua));
|
|
826
|
-
|
|
827
|
-
(tur, tug, tub, tua) = (fur, fug, fub, fua);
|
|
828
|
-
(fur, fug, fub, fua) = (cur, cug, cub, cua);
|
|
829
|
-
(por, pog, pob, poa) = (cor, cog, cob, coa);
|
|
830
|
-
|
|
831
|
-
cor = *o8.add(ooffset) as f32;
|
|
832
|
-
cog = *o8.add(1 + ooffset) as f32;
|
|
833
|
-
cob = *o8.add(2 + ooffset) as f32;
|
|
834
|
-
coa = *o8.add(3 + ooffset) as f32;
|
|
835
|
-
*u8.add(offset) = fi(fa(fur, *f32.offset(toffset)));
|
|
836
|
-
*u8.add(1 + offset) = fi(fa(fug, *f32.offset(1 + toffset)));
|
|
837
|
-
*u8.add(2 + offset) = fi(fa(fub, *f32.offset(2 + toffset)));
|
|
838
|
-
*u8.add(3 + offset) = fi(fa(fua, *f32.offset(3 + toffset)));
|
|
839
|
-
|
|
840
|
-
ooffset = ooffset.saturating_sub(4);
|
|
841
|
-
toffset = toffset.saturating_sub(4);
|
|
842
|
-
offset = offset.saturating_sub(height4);
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
pub mod quant {
|
|
850
|
-
use super::*;
|
|
851
|
-
|
|
852
|
-
struct bin { r: u32, g: u32, b: u32, a: u32, count: u32 }
|
|
853
|
-
|
|
854
|
-
struct tbin {
|
|
855
|
-
n: u32, p: u32,
|
|
856
|
-
r: f32, g: f32, b: f32, a: f32,
|
|
857
|
-
la: u32, lb: u32, error: f32, count: f32, nearest: u32,
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
pub struct result {
|
|
861
|
-
pub index: Vec<u8>,
|
|
862
|
-
pub palette: Vec<colors::rgba>,
|
|
863
|
-
pub transparency: Option<usize>,
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
pub struct options {
|
|
867
|
-
pub fast: bool,
|
|
868
|
-
pub dither: bool,
|
|
869
|
-
pub colors: usize,
|
|
870
|
-
pub transparency: bool,
|
|
871
|
-
pub threshold: Option<u8>,
|
|
872
|
-
pub force_transparency: bool,
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
impl Default for options {
|
|
876
|
-
fn default() -> Self {
|
|
877
|
-
return Self {
|
|
878
|
-
fast: false,
|
|
879
|
-
colors: 256,
|
|
880
|
-
dither: true,
|
|
881
|
-
threshold: None,
|
|
882
|
-
transparency: true,
|
|
883
|
-
force_transparency: false,
|
|
884
|
-
};
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
unsafe fn index(fb: &fb, _colors: usize, opt: &options, palette: &[colors::rgba], s: &(f32, f32, f32, f32)) -> Vec<u8> {
|
|
889
|
-
let mut index: Vec<u8> = Vec::with_capacity(fb.width * fb.height);
|
|
890
|
-
|
|
891
|
-
let u8 = index.as_mut_ptr();
|
|
892
|
-
let u32 = fb.as_ptr::<u32>();
|
|
893
|
-
index.set_len(fb.width * fb.height);
|
|
894
|
-
let mut nearest: fnv::FnvHashMap<u32, u8> = fnv::FnvHashMap::default();
|
|
895
|
-
let mut closest: fnv::FnvHashMap<u32, (u8, u8, f32, f32)> = fnv::FnvHashMap::default();
|
|
896
|
-
|
|
897
|
-
if opt.fast { for o in 0..(fb.len() / 4) { *u8.add(o) = self::nearest(*u32.add(o), &palette, &s, &mut nearest); } }
|
|
898
|
-
else { for o in 0..(fb.len() / 4) { *u8.add(o) = self::closest(*u32.add(o), o, &palette, &s, &mut nearest, &mut closest); } }
|
|
899
|
-
|
|
900
|
-
return index;
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
unsafe fn link_neareast(o: usize, bins: *mut tbin, s: &(f32, f32, f32, f32)) {
|
|
904
|
-
let mut nearest = 0;
|
|
905
|
-
let mut e = f32::INFINITY;
|
|
906
|
-
let bin = &mut *bins.add(o);
|
|
907
|
-
|
|
908
|
-
let n1 = bin.count;
|
|
909
|
-
let mut offset = bin.n;
|
|
910
|
-
let w = (bin.r, bin.g, bin.b, bin.a);
|
|
911
|
-
|
|
912
|
-
while 0 != offset {
|
|
913
|
-
let b = &*bins.add(offset as usize);
|
|
914
|
-
|
|
915
|
-
let mut err =
|
|
916
|
-
s.0 * (b.r - w.0).powi(2)
|
|
917
|
-
+ s.1 * (b.g - w.1).powi(2)
|
|
918
|
-
+ s.2 * (b.b - w.2).powi(2)
|
|
919
|
-
+ s.3 * (b.a - w.3).powi(2);
|
|
920
|
-
|
|
921
|
-
let n2 = b.count;
|
|
922
|
-
err *= (n1 * n2) / (n1 + n2);
|
|
923
|
-
if e > err { e = err; nearest = offset; }
|
|
924
|
-
offset = (*bins.offset(offset as isize)).n;
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
bin.error = e;
|
|
928
|
-
bin.nearest = nearest;
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
unsafe fn nearest(c: u32, palette: &[colors::rgba], s: &(f32, f32, f32, f32), cache: &mut fnv::FnvHashMap<u32, u8>) -> u8 {
|
|
932
|
-
let old = cache.get(&c);
|
|
933
|
-
if old.is_some() { return *old.unwrap_unchecked(); }
|
|
934
|
-
|
|
935
|
-
let a = (c >> 24) as f32;
|
|
936
|
-
let r = (c & 0xff) as f32;
|
|
937
|
-
let g = ((c >> 8) & 0xff) as f32;
|
|
938
|
-
let b = ((c >> 16) & 0xff) as f32;
|
|
939
|
-
|
|
940
|
-
let mut offset = 0;
|
|
941
|
-
let p = palette.as_ptr();
|
|
942
|
-
let mut m = f32::INFINITY;
|
|
943
|
-
|
|
944
|
-
for o in 0..palette.len() {
|
|
945
|
-
let cc = *p.add(o);
|
|
946
|
-
let rr = cc.r as f32;
|
|
947
|
-
let gg = cc.g as f32;
|
|
948
|
-
let bb = cc.b as f32;
|
|
949
|
-
let aa = cc.a as f32;
|
|
950
|
-
let mut d = s.3 * (aa - a).powi(2);
|
|
951
|
-
|
|
952
|
-
if d > m { continue; }
|
|
953
|
-
d += s.0 * (rr - r).powi(2); if d > m { continue; }
|
|
954
|
-
d += s.1 * (gg - g).powi(2); if d > m { continue; }
|
|
955
|
-
d += s.2 * (bb - b).powi(2); if d > m { continue; }
|
|
956
|
-
|
|
957
|
-
m = d; offset = o as u8;
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
cache.insert(c, offset); return offset;
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
unsafe fn closest(c: u32, o: usize, palette: &[colors::rgba], s: &(f32, f32, f32, f32), nearest: &mut fnv::FnvHashMap<u32, u8>, cache: &mut fnv::FnvHashMap<u32, (u8, u8, f32, f32)>) -> u8 {
|
|
964
|
-
let old = cache.get(&c);
|
|
965
|
-
|
|
966
|
-
let m = if old.is_some() { *old.unwrap_unchecked() } else {
|
|
967
|
-
let a = (c >> 24) as f32;
|
|
968
|
-
let r = (c & 0xff) as f32;
|
|
969
|
-
let pp = palette.as_ptr();
|
|
970
|
-
let g = ((c >> 8) & 0xff) as f32;
|
|
971
|
-
let b = ((c >> 16) & 0xff) as f32;
|
|
972
|
-
let mut m = (0u8, 0u8, f32::INFINITY, f32::INFINITY);
|
|
973
|
-
|
|
974
|
-
for o in 0..palette.len() {
|
|
975
|
-
let cc = *pp.add(o);
|
|
976
|
-
let rr = cc.r as f32;
|
|
977
|
-
let gg = cc.g as f32;
|
|
978
|
-
let bb = cc.b as f32;
|
|
979
|
-
let aa = cc.a as f32;
|
|
980
|
-
let err = s.0 * (rr - r).powi(2) + s.1 * (gg - g).powi(2) + s.2 * (bb - b).powi(2) + s.3 * (aa - a).powi(2);
|
|
981
|
-
if m.2 > err { m.1 = m.0; m.3 = m.2; m.2 = err; m.0 = o as u8; } else if m.3 > err { m.3 = err; m.1 = o as u8; }
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
if m.3 == f32::INFINITY { m.1 = m.0; } cache.insert(c, m); m
|
|
985
|
-
};
|
|
986
|
-
|
|
987
|
-
let l = palette.len();
|
|
988
|
-
let mut oo = (1 + o) % 2;
|
|
989
|
-
if m.3 * 0.67 < (m.3 - m.2) { oo = 0 } else if m.0 > m.1 { oo = o % 2; }
|
|
990
|
-
|
|
991
|
-
let err = match oo { 0 => m.2, 1 => m.3, _ => unreachable() };
|
|
992
|
-
if err >= l as f32 { return self::nearest(c, palette, s, nearest); }
|
|
993
|
-
|
|
994
|
-
return match oo { 0 => m.0, 1 => m.1, _ => unreachable() };
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
pub fn quantize(fb: &fb, options: &options) -> result {
|
|
998
|
-
let width = fb.width;
|
|
999
|
-
let height = fb.height;
|
|
1000
|
-
let mut fb = fb.clone();
|
|
1001
|
-
let u32 = fb.as_mut_ptr::<u32>();
|
|
1002
|
-
let colors = options.colors.clamp(2, 256);
|
|
1003
|
-
let mut s = (0.2126, 0.7152, 0.0722, 0.3333);
|
|
1004
|
-
|
|
1005
|
-
if 32 >= colors { s = (1.0, 1.0, 1.0, 1.0); }
|
|
1006
|
-
else if 512 > width || 512 > height { s = (0.299, 0.587, 0.114, s.3); }
|
|
1007
|
-
|
|
1008
|
-
unsafe {
|
|
1009
|
-
if !options.transparency {
|
|
1010
|
-
s.3 = 0.0;
|
|
1011
|
-
let threshold = options.threshold.unwrap_or(0x42) as u32;
|
|
1012
|
-
|
|
1013
|
-
for o in 0..(fb.len() / 4) {
|
|
1014
|
-
let a = *u32.add(o) >> 24;
|
|
1015
|
-
*u32.add(0) = (if a < threshold { 0 } else { *u32.add(o) & 0xffffff }) | (255 << 24);
|
|
1016
|
-
}
|
|
1017
|
-
} else {
|
|
1018
|
-
if options.threshold.is_none() {
|
|
1019
|
-
for o in 0..(fb.len() / 4) {
|
|
1020
|
-
let a = *u32.add(o) >> 24;
|
|
1021
|
-
if a == 0 { *u32.add(0) = 0xffffff; }
|
|
1022
|
-
}
|
|
1023
|
-
} else {
|
|
1024
|
-
let threshold = options.threshold.unwrap_unchecked() as u32;
|
|
1025
|
-
|
|
1026
|
-
for o in 0..(fb.len() / 4) {
|
|
1027
|
-
let a = *u32.add(o) >> 24;
|
|
1028
|
-
*u32.add(0) = if a < threshold { 0xffffff } else { *u32.add(o) & 0xffffff | (255 << 24) };
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
let mut palette: Vec<colors::rgba> = vec![0.into(); colors];
|
|
1035
|
-
|
|
1036
|
-
if 2 < colors {
|
|
1037
|
-
let (mut s, p) = unsafe { self::palette(&fb, colors, &options, &mut s) };
|
|
1038
|
-
|
|
1039
|
-
unsafe {
|
|
1040
|
-
let ss = s;
|
|
1041
|
-
let mut t = -1;
|
|
1042
|
-
for o in 0..s { if 0 == (*p.add(o) >> 24) { t = o as isize; break; } }
|
|
1043
|
-
if t == -1 && options.transparency && options.force_transparency { *p.add(if s == colors { s - 1 } else { s += 1; s - 1 }) = 0; }
|
|
1044
|
-
|
|
1045
|
-
palette.as_mut_ptr().copy_from_nonoverlapping(p as _, s); palette.set_len(s);
|
|
1046
|
-
|
|
1047
|
-
free(p as *mut u8, ss);
|
|
1048
|
-
palette.sort_by(|&a, &b| u32::cmp(&b.into(), &a.into()));
|
|
1049
|
-
}
|
|
1050
|
-
} else {
|
|
1051
|
-
unsafe {
|
|
1052
|
-
*palette.get_unchecked_mut(0) = colors::rgba { r: 0, g: 0, b: 0, a: 255 };
|
|
1053
|
-
|
|
1054
|
-
let mut t = options.transparency && options.force_transparency;
|
|
1055
|
-
if !t && options.transparency { for o in 0..(fb.len() / 4) { if 0 == (*u32.add(o) >> 24) { t = true; break; } } }
|
|
1056
|
-
|
|
1057
|
-
*palette.get_unchecked_mut(1) =
|
|
1058
|
-
if t { colors::rgba { r: 255, g: 255, b: 255, a: 0 } }
|
|
1059
|
-
else { colors::rgba { r: 255, g: 255, b: 255, a: 255 } };
|
|
1060
|
-
}
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
let mut t = None;
|
|
1064
|
-
let index = unsafe { index(&fb, colors, &options, &palette, &s) };
|
|
1065
|
-
for o in 0..palette.len() { if 0 == palette[o].a { t = Some(o); break; } }
|
|
1066
|
-
|
|
1067
|
-
return result {
|
|
1068
|
-
index,
|
|
1069
|
-
palette,
|
|
1070
|
-
transparency: t,
|
|
1071
|
-
};
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
unsafe fn palette(fb: &fb, colors: usize, options: &options, s: &mut (f32, f32, f32, f32)) -> (usize, *mut u32) {
|
|
1075
|
-
let u32 = fb.as_ptr::<u32>();
|
|
1076
|
-
const BINS: usize = 2usize.pow(16);
|
|
1077
|
-
|
|
1078
|
-
let (size, bins): (usize, *mut tbin) = {
|
|
1079
|
-
let bins = calloc(BINS * size_of!(bin)) as *mut bin;
|
|
1080
|
-
|
|
1081
|
-
let index = match options.fast {
|
|
1082
|
-
true => |r: u32, g: u32, b: u32, a: u32| ((r & 0xF0) << 4) | (g & 0xF0) | (b >> 4) | ((a & 0xF0) << 8),
|
|
1083
|
-
|
|
1084
|
-
false => match 64 <= colors && !options.transparency {
|
|
1085
|
-
true => |r: u32, g: u32, b: u32, _: u32| ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3),
|
|
1086
|
-
false => |r: u32, g: u32, b: u32, a: u32| ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | (b >> 3) | ((a & 0x80) << 8),
|
|
1087
|
-
},
|
|
1088
|
-
};
|
|
1089
|
-
|
|
1090
|
-
for o in 0..(fb.len() / 4) {
|
|
1091
|
-
let c = *u32.add(o);
|
|
1092
|
-
|
|
1093
|
-
let a = c >> 24;
|
|
1094
|
-
let r = c & 0xff;
|
|
1095
|
-
let g = (c >> 8) & 0xff;
|
|
1096
|
-
let b = (c >> 16) & 0xff;
|
|
1097
|
-
|
|
1098
|
-
let mut bin = &mut *bins.add(index(r, g, b, a) as usize);
|
|
1099
|
-
|
|
1100
|
-
bin.r += r;
|
|
1101
|
-
bin.g += g;
|
|
1102
|
-
bin.b += b;
|
|
1103
|
-
bin.a += a;
|
|
1104
|
-
bin.count += 1;
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
let mut size = 0;
|
|
1108
|
-
|
|
1109
|
-
for o in 0..BINS {
|
|
1110
|
-
let bin = bins.add(o);
|
|
1111
|
-
if 0 == (*bin).count { continue; }
|
|
1112
|
-
bins.add(size).copy_from(bin, 1); size += 1;
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
let tbin = calloc(size * size_of!(tbin)) as *mut tbin;
|
|
1116
|
-
|
|
1117
|
-
for o in 0..size {
|
|
1118
|
-
use std::intrinsics::{fdiv_fast as fd};
|
|
1119
|
-
|
|
1120
|
-
let bin = &*bins.add(o);
|
|
1121
|
-
let tbin = &mut *tbin.add(o);
|
|
1122
|
-
|
|
1123
|
-
let count = bin.count as f32;
|
|
1124
|
-
|
|
1125
|
-
tbin.count = count;
|
|
1126
|
-
tbin.r = fd(bin.r as f32, count);
|
|
1127
|
-
tbin.g = fd(bin.g as f32, count);
|
|
1128
|
-
tbin.b = fd(bin.b as f32, count);
|
|
1129
|
-
tbin.a = fd(bin.a as f32, count);
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
free(bins as *mut u8, BINS * size_of!(bin));
|
|
1133
|
-
|
|
1134
|
-
(size, tbin)
|
|
1135
|
-
};
|
|
1136
|
-
|
|
1137
|
-
let q = {
|
|
1138
|
-
let weight = colors as f32 / size as f32;
|
|
1139
|
-
let mut e = if 16 <= colors { 1 } else { -1 };
|
|
1140
|
-
if 0.003 < weight && 0.005 > weight { e = 0; };
|
|
1141
|
-
|
|
1142
|
-
if s.1 < 1.0 && 0.025 > weight {
|
|
1143
|
-
s.1 -= 3.0 * (0.025 + weight);
|
|
1144
|
-
s.2 += 3.0 * (0.025 + weight);
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
match e {
|
|
1148
|
-
0 => |count: f32| count,
|
|
1149
|
-
-1 => |count: f32| count.cbrt() as u32 as f32,
|
|
1150
|
-
|
|
1151
|
-
1 => match 64 > colors {
|
|
1152
|
-
true => |count: f32| count.sqrt(),
|
|
1153
|
-
false => |count: f32| count.sqrt() as u32 as f32,
|
|
1154
|
-
},
|
|
1155
|
-
|
|
1156
|
-
_ => unreachable(),
|
|
1157
|
-
}
|
|
1158
|
-
};
|
|
1159
|
-
|
|
1160
|
-
for o in 0..(size - 1) {
|
|
1161
|
-
let bin = &mut *bins.add(o);
|
|
1162
|
-
|
|
1163
|
-
bin.n = (o + 1) as u32;
|
|
1164
|
-
bin.count = q(bin.count);
|
|
1165
|
-
(*bins.add(o + 1)).p = o as u32;
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
(*bins.add(size - 1)).count = q((*bins.add(size - 1)).count);
|
|
1169
|
-
|
|
1170
|
-
let heap = calloc(4 * (1 + BINS)) as *mut u32;
|
|
1171
|
-
|
|
1172
|
-
for o in 0..size {
|
|
1173
|
-
link_neareast(o, bins, &s);
|
|
1174
|
-
let err = (*bins.add(o)).error;
|
|
1175
|
-
|
|
1176
|
-
*heap += 1;
|
|
1177
|
-
let mut l = *heap;
|
|
1178
|
-
|
|
1179
|
-
while 1 < l {
|
|
1180
|
-
let h = *heap.add((l >> 1) as usize);
|
|
1181
|
-
if err >= (*bins.add(h as usize)).error { break; }
|
|
1182
|
-
|
|
1183
|
-
*heap.add(l as usize) = h; l >>= 1;
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
|
-
*heap.add(l as usize) = o as u32;
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
let ext = size as isize - colors as isize;
|
|
1190
|
-
|
|
1191
|
-
for o in 0..ext {
|
|
1192
|
-
let mut b;
|
|
1193
|
-
|
|
1194
|
-
loop {
|
|
1195
|
-
b = *heap.add(1);
|
|
1196
|
-
let tb = &mut *bins.add(b as usize);
|
|
1197
|
-
if (tb.la >= tb.lb) && (tb.la >= (*bins.add(tb.nearest as usize)).lb) { break; }
|
|
1198
|
-
|
|
1199
|
-
if tb.lb == 0xffff {
|
|
1200
|
-
*heap -= 1;
|
|
1201
|
-
let h = 1 + *heap;
|
|
1202
|
-
b = *heap.add(h as usize);
|
|
1203
|
-
*heap.offset(1) = *heap.add(h as usize);
|
|
1204
|
-
} else { link_neareast(b as usize, bins, &s); tb.la = o as u32; }
|
|
1205
|
-
|
|
1206
|
-
let mut l = 1;
|
|
1207
|
-
let err = (*bins.add(b as usize)).error;
|
|
1208
|
-
|
|
1209
|
-
while l + l <= *heap {
|
|
1210
|
-
let mut l2 = l + l;
|
|
1211
|
-
if (l2 < *heap) && ((*bins.add(*heap.add(l2 as usize) as usize)).error > (*bins.add(*heap.add(1 + l2 as usize) as usize)).error) { l2 += 1 }
|
|
1212
|
-
|
|
1213
|
-
let h = *heap.add(l2 as usize);
|
|
1214
|
-
if err <= (*bins.add(h as usize)).error { break; }
|
|
1215
|
-
|
|
1216
|
-
*heap.add(l as usize) = h; l = l2;
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
*heap.add(l as usize) = b;
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
|
-
let tb = &mut *bins.add(b as usize);
|
|
1223
|
-
let nb = &mut *bins.add(tb.nearest as usize);
|
|
1224
|
-
|
|
1225
|
-
let n1 = tb.count;
|
|
1226
|
-
let n2 = nb.count;
|
|
1227
|
-
let d = 1.0 / (n1 + n2);
|
|
1228
|
-
tb.r = d * (n1 * tb.r + n2 * nb.r).round();
|
|
1229
|
-
tb.g = d * (n1 * tb.g + n2 * nb.g).round();
|
|
1230
|
-
tb.b = d * (n1 * tb.b + n2 * nb.b).round();
|
|
1231
|
-
tb.a = d * (n1 * tb.a + n2 * nb.a).round();
|
|
1232
|
-
|
|
1233
|
-
nb.lb = 0xffff;
|
|
1234
|
-
tb.count += nb.count;
|
|
1235
|
-
tb.lb = (o + 1) as u32;
|
|
1236
|
-
|
|
1237
|
-
(*bins.add(nb.p as usize)).n = nb.n;
|
|
1238
|
-
(*bins.add(nb.n as usize)).p = nb.p;
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
free(heap as *mut u8, 4 * (1 + BINS));
|
|
1242
|
-
let s = if 0 > ext { size } else { colors };
|
|
1243
|
-
let palette = alloc(s * size_of!(colors::rgba)) as *mut colors::rgba;
|
|
1244
|
-
|
|
1245
|
-
let mut w = 0;
|
|
1246
|
-
let mut offset = 0;
|
|
1247
|
-
|
|
1248
|
-
loop {
|
|
1249
|
-
let r = (*bins.add(offset)).r.clamp(0.0, 255.0) as u8;
|
|
1250
|
-
let g = (*bins.add(offset)).g.clamp(0.0, 255.0) as u8;
|
|
1251
|
-
let b = (*bins.add(offset)).b.clamp(0.0, 255.0) as u8;
|
|
1252
|
-
let a = (*bins.add(offset)).a.clamp(0.0, 255.0) as u8;
|
|
1253
|
-
|
|
1254
|
-
*palette.add(w) = colors::rgba { r, g, b, a };
|
|
1255
|
-
|
|
1256
|
-
w += 1;
|
|
1257
|
-
offset = (*bins.add(offset)).n as usize;
|
|
1258
|
-
|
|
1259
|
-
if 0 == offset { break; }
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
return (s, palette as *mut u32);
|
|
1263
|
-
}
|
|
1264
|
-
}
|