Skip to content

Commit 446f47f

Browse files
committed
resize opt
1 parent 75b888f commit 446f47f

File tree

3 files changed

+92
-17
lines changed

3 files changed

+92
-17
lines changed

app/index.html

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@
1616
<br>
1717
<label for="secretInput">Secret:</label>
1818
<input id="secretInput" placeholder="Enter your secret here" autocomplete="off">
19+
20+
<span style="margin-top: 0.25rem">
21+
<input type="checkbox" id="limitMaxSide" checked>
22+
<label for="limitMaxSide">Limit max side to </label>
23+
<input type="number" id="maxSide" value="1024" min="1" max="25565" step="1" style="width: 4em;">
24+
<label for="maxSide">px</label>
25+
</span>
1926
</div>
2027

2128
<div id="button-container">
@@ -34,6 +41,13 @@
3441
<div id="error"></div>
3542
</div>
3643

44+
<div id="footer">
45+
<p style="text-align: center; font-size: 0.8em; color: #666">
46+
The code runs entirely in your browser using WebAssembly. <br>
47+
The source code is available at <a href="https://github.com/MenxLi/chaotic-enc">menxli/chaotic-enc</a>.
48+
</p>
49+
</div>
50+
3751
</body>
3852

3953
<script type="module">
@@ -43,6 +57,8 @@
4357

4458
const secretInput = document.getElementById('secretInput');
4559
const fileInput = document.getElementById('fileInput');
60+
const limitMaxSideInput = document.getElementById('limitMaxSide');
61+
const maxSideInput = document.getElementById('maxSide');
4662
const inputImgDiv = document.getElementById('inputImg');
4763
const outputDiv = document.getElementById('output');
4864
const hintLabel = document.getElementById('hint');
@@ -99,14 +115,14 @@
99115

100116
const imgElem = document.createElement('img');
101117
imgElem.src = url;
102-
imgElem.alt = 'Encoded Image';
118+
imgElem.alt = 'Image';
103119
outputDiv.appendChild(imgElem);
104120

105121
downloadBtn.style.display = 'block';
106122
downloadBtn.onclick = () => {
107123
const a = document.createElement('a');
108124
a.href = url;
109-
a.download = 'encoded_image.png';
125+
a.download = 'image.png';
110126
document.body.appendChild(a);
111127
a.click();
112128
document.body.removeChild(a);
@@ -118,15 +134,25 @@
118134
resetOutput();
119135
const inputBlob = await getInputBlob();
120136
hintLabel.textContent = `Encoding...`;
121-
worker.postMessage({type: 'encode', buffer: inputBlob, secret: secretInput.value });
137+
worker.postMessage({
138+
type: 'encode',
139+
buffer: inputBlob,
140+
secret: secretInput.value,
141+
maxSide: limitMaxSideInput.checked ? parseInt(maxSideInput.value) : -1
142+
});
122143
}
123144

124145
async function decode_image() {
125146
checkInput();
126147
resetOutput();
127148
const inputBlob = await getInputBlob();
128149
hintLabel.textContent = `Decoding...`;
129-
worker.postMessage({type: 'decode', buffer: inputBlob, secret: secretInput.value });
150+
worker.postMessage({
151+
type: 'decode',
152+
buffer: inputBlob,
153+
secret: secretInput.value,
154+
maxSide: limitMaxSideInput.checked ? parseInt(maxSideInput.value) : -1
155+
});
130156
}
131157

132158
worker.onmessage = async (event) => {

app/worker.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@ import init, { encode, decode } from './pkg/chaotic_enc.js';
22

33
await init();
44
self.onmessage = async function(event) {
5-
const { type, buffer, secret } = event.data;
5+
const { type, buffer, secret, maxSide } = event.data;
6+
7+
console.log('Worker received message:', event.data);
68

79
if (type === 'encode') {
8-
const encoded = encode(buffer, secret);
10+
const encoded = encode(buffer, secret, maxSide);
911
self.postMessage({ type: 'encoded', buffer: encoded });
1012
}
1113

1214
if (type === 'decode') {
13-
const decoded = decode(buffer, secret);
15+
const decoded = decode(buffer, secret, maxSide);
1416
self.postMessage({ type: 'decoded', buffer: decoded });
1517
}
1618
}

src/lib.rs

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,20 @@ use std::u8;
66
use wasm_bindgen::prelude::*;
77
use image::{self, ImageEncoder};
88

9+
// https://rustwasm.github.io/wasm-bindgen/examples/console-log.html
10+
#[wasm_bindgen]
11+
extern "C" {
12+
#[wasm_bindgen(js_namespace = console)]
13+
fn log(s: &str);
14+
#[wasm_bindgen(js_namespace = console, js_name = log)]
15+
fn log_u32(a: u32);
16+
#[wasm_bindgen(js_namespace = console, js_name = log)]
17+
fn log_many(a: &str, b: &str);
18+
}
19+
macro_rules! console_log {
20+
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
21+
}
22+
923
pub struct ImageOptions {
1024
pub width: u32,
1125
pub height: u32,
@@ -19,9 +33,23 @@ fn str2f(s: &str) -> f32 {
1933
x
2034
}
2135

22-
fn img2vec(im: &[u8]) -> (Vec<[u8; 3]>, ImageOptions) {
36+
fn img2vec(im: &[u8], limit_max_side: Option<u32>) -> (Vec<[u8; 3]>, ImageOptions) {
2337
let img = image::load_from_memory(im).expect("Failed to load image");
24-
let rgb = img.to_rgb8();
38+
let mut rgb = img.to_rgb8();
39+
40+
if let Some(max_side) = limit_max_side {
41+
let (mut width, mut height) = rgb.dimensions();
42+
if width > max_side || height > max_side {
43+
let scale = max_side as f32 / width.max(height) as f32;
44+
width = (width as f32 * scale).round() as u32;
45+
height = (height as f32 * scale).round() as u32;
46+
rgb = image::imageops::resize(
47+
&rgb, width, height,
48+
image::imageops::FilterType::Lanczos3
49+
);
50+
}
51+
}
52+
2553
let mut pixels = Vec::with_capacity(rgb.width() as usize * rgb.height() as usize);
2654
for pixel in rgb.pixels() {
2755
pixels.push([pixel[0], pixel[1], pixel[2]]);
@@ -33,8 +61,8 @@ fn img2vec(im: &[u8]) -> (Vec<[u8; 3]>, ImageOptions) {
3361
})
3462
}
3563

36-
fn vec2pngblob(pixels: &Vec<[u8; 3]>, im_opt: ImageOptions) -> Box<[u8]> {
37-
let ImageOptions { width, height } = im_opt;
64+
fn vec2pngblob(pixels: &Vec<[u8; 3]>, im_opt: ImageOptions, limit_max_side: Option<u32>) -> Box<[u8]> {
65+
let ImageOptions { mut width, mut height } = im_opt;
3866

3967
let mut img = image::RgbImage::new(width, height);
4068
for (i, pixel) in pixels.iter().enumerate() {
@@ -43,6 +71,18 @@ fn vec2pngblob(pixels: &Vec<[u8; 3]>, im_opt: ImageOptions) -> Box<[u8]> {
4371
img.put_pixel(x, y, image::Rgb(*pixel));
4472
};
4573

74+
if let Some(max_side) = limit_max_side {
75+
if width > max_side || height > max_side {
76+
let scale = max_side as f32 / width.max(height) as f32;
77+
width = (width as f32 * scale).round() as u32;
78+
height = (height as f32 * scale).round() as u32;
79+
img = image::imageops::resize(
80+
&img, width, height,
81+
image::imageops::FilterType::Lanczos3
82+
);
83+
}
84+
}
85+
4686
// Encode the image to PNG format
4787
let mut buf = Vec::new();
4888
let encoder = image::codecs::png::PngEncoder::new(&mut buf);
@@ -53,29 +93,36 @@ fn vec2pngblob(pixels: &Vec<[u8; 3]>, im_opt: ImageOptions) -> Box<[u8]> {
5393
image::ExtendedColorType::Rgb8,
5494
).expect("Failed to encode image");
5595

96+
console_log!("Export image, dimensions: {}x{}", width, height);
5697
buf.into_boxed_slice()
5798
}
5899

59100
#[wasm_bindgen]
60-
pub fn encode(im: &[u8], secret: &str) -> Box<[u8]> {
61-
let (mut im_v, im_opt) = img2vec(im);
101+
pub fn encode(im: &[u8], secret: &str, max_side: i32) -> Box<[u8]> {
102+
console_log!("Encoding image with secret: {}, max_side: {}", secret, max_side);
103+
let max_side = if max_side < 1 { None } else { Some(max_side as u32) };
104+
105+
let (mut im_v, im_opt) = img2vec(im, max_side);
62106

63107
let pixels = logistic_map::encode(
64108
&mut im_v,
65109
str2f(&secret)
66110
);
67111

68-
vec2pngblob(&pixels, im_opt)
112+
vec2pngblob(&pixels, im_opt, None)
69113
}
70114

71115
#[wasm_bindgen]
72-
pub fn decode(im: &[u8], secret: &str) -> Box<[u8]> {
73-
let (im_v, im_opt) = img2vec(im);
116+
pub fn decode(im: &[u8], secret: &str, max_side: i32) -> Box<[u8]> {
117+
console_log!("Decoding image with secret: {}, max_side: {}", secret, max_side);
118+
let max_side = if max_side < 1 { None } else { Some(max_side as u32) };
119+
120+
let (im_v, im_opt) = img2vec(im, None);
74121

75122
let pixels = logistic_map::decode(
76123
&im_v,
77124
str2f(&secret)
78125
);
79126

80-
vec2pngblob(&pixels, im_opt)
127+
vec2pngblob(&pixels, im_opt, max_side)
81128
}

0 commit comments

Comments
 (0)