Skip to content

Commit 8d266a2

Browse files
committed
Deploying to gh-pages from @ d00d95a 🚀
1 parent 1e9ad68 commit 8d266a2

8 files changed

Lines changed: 215 additions & 77 deletions

File tree

FEATURES.md

Lines changed: 0 additions & 8 deletions
This file was deleted.

index.html

Lines changed: 180 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@
3434
border-radius: 3px;
3535
padding: 6px;
3636
}
37+
38+
#inputSection {
39+
border: 2px dashed var(--main-border-color);
40+
color: var(--main-border-color);
41+
padding: 1em;
42+
}
43+
44+
#inputSection:hover {
45+
border: 2px dashed var(--main-draw-color);
46+
color: var(--main-draw-color);
47+
}
3748

3849
@keyframes shake {
3950
0% { transform: translateX(0); }
@@ -93,6 +104,22 @@
93104
}
94105
}
95106

107+
#convertBtn {
108+
margin-top: 0.5em;
109+
}
110+
111+
#advancedInput {
112+
* {
113+
margin-bottom: 0.5em;
114+
}
115+
}
116+
117+
#actionSection {
118+
display: flex;
119+
flex-direction: column;
120+
align-items: center;
121+
}
122+
96123
</style>
97124
</head>
98125
<body>
@@ -103,78 +130,85 @@ <h1>Offline Image Converter</h1>
103130
<li>Everything stays on your device, private and secure</li>
104131
</ul>
105132

106-
<p>Paste an image using CTLR-V or choose a image from:</p>
107-
108-
<input type="file" id="fileInput" accept="image/bmp,image/x-bmp,image/vnd-ms.dds,image/x-direct-draw-surface,image/x-exr,image/ff,image/gif,image/vnd.radiance,image/x-icon,image/jpeg,image/png,image/x-portable-bitmap,image/x-portable-graymap,image/x-portable-pixmap,image/x-portable-anymap,image/qoi,image/x-tga,image/x-targa,image/tiff,image/tiff-fx,image/webp" />
133+
<hr style="width: 35em;">
109134

110-
<div id="filePasteSection" style="display: none;">
111-
<p>Pasted file</p>
112-
<button onclick="resetPaste()">Reset</button>
113-
</div>
135+
<p>Paste an image using CTLR-V or choose a image from:</p>
114136

115-
<div id="outputSection">
116-
<label for="outputType">Output format:</label>
117-
<select id="outputType">
118-
119-
<optgroup label="Most used:">
120-
<option value="image/jpeg">JPEG</option>
121-
<option value="image/png">PNG</option>
122-
</optgroup>
123-
124-
<optgroup label="More:">
125-
<option value="image/avif">AVIF</option>
126-
<option value="image/bmp">BMP</option>
127-
<option value="image/x-exr">OpenEXR</option>
128-
<option value="image/ff">Farbfeld</option>
129-
<option value="image/gif">GIF</option>
130-
<option value="image/vnd.radiance">HDR</option>
131-
<option value="image/x-icon">ICO</option>
132-
<option value="image/x-portable-bitmap">PNM</option>
133-
<option value="image/qoi">QOI</option>
134-
<option value="image/x-tga">TGA</option>
135-
<option value="image/tiff">TIFF</option>
136-
<option value="image/webp">WebP</option>
137-
</optgroup>
138-
</select>
139-
</div>
137+
<div id="inputSection">
138+
<input type="file" id="fileInput" onchange="fileInputChanged(event)" accept="image/bmp,image/x-bmp,image/vnd-ms.dds,image/x-direct-draw-surface,image/x-exr,image/ff,image/gif,image/vnd.radiance,image/x-icon,image/jpeg,image/png,image/x-portable-bitmap,image/x-portable-graymap,image/x-portable-pixmap,image/x-portable-anymap,image/qoi,image/x-tga,image/x-targa,image/tiff,image/tiff-fx,image/webp" />
140139

141-
<details id="advancedInput">
142-
<summary>
143-
Advanced options (click to expand)
144-
</summary>
145-
<div>
146-
<label for="quality">Quality (0-100, where 100 is best quality):</label>
147-
<input type="number" id="quality" name="quality" min="0" max="100" />
140+
<div id="filePasteSection" style="display: none;">
141+
<p>Pasted file</p>
142+
<button onclick="resetPaste()">Reset</button>
148143
</div>
144+
</div>
149145

150-
<div>
151-
<label for="compression">Compression method:</label>
152-
<select id="compression" name="compression">
153-
<option value="fast">Fast</option>
154-
<option value="best">Best</option>
155-
<option value="default">Default</option>
146+
<div id="actionSection" style="display: none;">
147+
<div id="outputSection">
148+
<label for="outputType">Output format:</label>
149+
<select id="outputType" onchange="selectChanged(event)">
150+
151+
<optgroup label="Most used:">
152+
<option value="image/jpeg">JPEG</option>
153+
<option value="image/png">PNG</option>
154+
</optgroup>
155+
156+
<optgroup label="More:">
157+
<option value="image/avif">AVIF</option>
158+
<option value="image/bmp">BMP</option>
159+
<option value="image/x-exr">OpenEXR</option>
160+
<option value="image/ff">Farbfeld</option>
161+
<option value="image/gif">GIF</option>
162+
<option value="image/vnd.radiance">HDR</option>
163+
<option value="image/x-icon">ICO</option>
164+
<option value="image/x-portable-bitmap">PNM</option>
165+
<option value="image/qoi">QOI</option>
166+
<option value="image/x-tga">TGA</option>
167+
<option value="image/tiff">TIFF</option>
168+
<option value="image/webp">WebP</option>
169+
</optgroup>
156170
</select>
157171
</div>
158172

159-
<div>
160-
<label for="filter">Filter type:</label>
161-
<select id="filter" name="filter">
162-
<option value="adaptive">Adaptive</option>
163-
<option value="no_filter">No filter</option>
164-
<option value="sub">Sub</option>
165-
<option value="up">Up</option>
166-
<option value="avg">Avg</option>
167-
<option value="paeth">Paeth</option>
168-
</select>
173+
<details id="advancedInput">
174+
<summary>
175+
Advanced options (click to expand)
176+
</summary>
177+
<div id="advancedInput-image/png" style="display: none;">
178+
<label for="quality">Quality (0 worst, 100 best):</label>
179+
<input type="number" id="quality" name="quality" min="0" max="100" value="100" />
180+
</div>
181+
182+
<div id="advancedInput-image/jpeg">
183+
<div>
184+
<label for="compression">Compression method:</label>
185+
<select id="compression" name="compression">
186+
<option value="fast">Fast</option>
187+
<option value="best">Best</option>
188+
<option value="default">Default</option>
189+
</select>
190+
</div>
191+
192+
<div>
193+
<label for="filter">Filter type:</label>
194+
<select id="filter" name="filter">
195+
<option value="adaptive">Adaptive</option>
196+
<option value="no_filter">No filter</option>
197+
<option value="sub">Sub</option>
198+
<option value="up">Up</option>
199+
<option value="avg">Avg</option>
200+
<option value="paeth">Paeth</option>
201+
</select>
202+
</div>
203+
</div>
204+
</details>
205+
206+
<button id="convertBtn" onclick="convert()">Convert</button>
207+
208+
<div id="loader" style="display: none;">
209+
<span class="loader"></span>
210+
<p id="progress">Starting...</p>
169211
</div>
170-
171-
</details>
172-
173-
<button id="convertBtn" onclick="convert()">Convert</button>
174-
175-
<div id="loader" style="display: none;">
176-
<span class="loader"></span>
177-
<p id="progress">Starting...</p>
178212
</div>
179213

180214
<p id="error-message" style="display: none;">
@@ -203,6 +237,14 @@ <h1>Offline Image Converter</h1>
203237
<script type="module">
204238
const worker = new Worker("./worker.js", { type: "module" });
205239

240+
const actionSection = document.getElementById("actionSection");
241+
function hideActions() {
242+
actionSection.style.display = 'none';
243+
}
244+
function showActions() {
245+
actionSection.style.display = 'flex';
246+
}
247+
206248
function downloadImage(imageData, fileName, outputType) {
207249
const blob = new Blob([imageData], { type: outputType });
208250
const url = URL.createObjectURL(blob);
@@ -242,6 +284,7 @@ <h1>Offline Image Converter</h1>
242284
}
243285

244286
if (type === "done") {
287+
hideError();
245288
downloadImage(imageData, fileName, outputType);
246289
} else if (type === "error") {
247290
showError(message);
@@ -276,6 +319,30 @@ <h1>Offline Image Converter</h1>
276319
return withoutExtension + "." + extension;
277320
}
278321

322+
const advancedQualityInput = document.getElementById("quality");
323+
const advancedCompressionInput = document.getElementById("compression");
324+
const advancedFilterInput = document.getElementById("filter");
325+
function getOptions() {
326+
const isOpen = advancedInput.open;
327+
if (!isOpen) {
328+
return {};
329+
}
330+
331+
if (outputTypeElement.value === "image/png") {
332+
const qualityInt = parseInt(advancedQualityInput.value);
333+
if (!isNaN(qualityInt)) {
334+
const quality = Math.min(100, Math.max(0, qualityInt));
335+
return { quality };
336+
}
337+
} else if (outputTypeElement.value === "image/jpeg") {
338+
const compression = advancedCompressionInput.value;
339+
const filter = advancedFilterInput.value;
340+
return { compression, filter };
341+
}
342+
343+
return {};
344+
}
345+
279346
let pasted = false;
280347

281348
const fileInput = document.getElementById('fileInput');
@@ -301,13 +368,15 @@ <h1>Offline Image Converter</h1>
301368
showLoader();
302369
hideError();
303370

371+
const options = getOptions(outputType);
372+
304373
const fileName = newFileName(file.name, outputType);
305374
const inputType = file.type;
306375
const imageDataBuffer = await file.arrayBuffer();
307376
const imageData = new Uint8Array(imageDataBuffer);
308377
const imageTransfer = imageData.buffer;
309-
310-
worker.postMessage({ imageData, fileName, inputType, outputType }, [imageTransfer]);
378+
379+
worker.postMessage({ imageData, fileName, inputType, outputType, options }, [imageTransfer]);
311380
}
312381
window.convert = convert;
313382

@@ -316,6 +385,8 @@ <h1>Offline Image Converter</h1>
316385
pasted = false;
317386
filePasteSection.style.display = 'none';
318387
fileInput.style.display = 'block';
388+
hideActions();
389+
hideError();
319390
}
320391
window.resetPaste = resetPaste;
321392

@@ -330,11 +401,55 @@ <h1>Offline Image Converter</h1>
330401
pasted = true;
331402

332403
fileInput.style.display = 'none';
404+
fileInput.value = null;
333405
filePasteSection.style.display = 'flex';
406+
fileInputChanged(file.type);
407+
showActions();
408+
hideError();
334409
}
335410
}
336411
});
337412

413+
const advancedInput = document.getElementById("advancedInput");
414+
function selectChanged(event) {
415+
const outputType = event.target.value;
416+
const advancedInputDivs = document.querySelectorAll("#advancedInput > div");
417+
advancedInputDivs.forEach(div => {
418+
div.style.display = 'none';
419+
});
420+
421+
let constainsAdvancedOptions = false;
422+
423+
const specificDiv = document.getElementById("advancedInput-" + outputType);
424+
if (specificDiv) {
425+
specificDiv.style.display = 'block';
426+
constainsAdvancedOptions = true;
427+
}
428+
429+
advancedInput.style.display = constainsAdvancedOptions ? 'block' : 'none';
430+
hideError();
431+
}
432+
window.selectChanged = selectChanged;
433+
434+
function fileInputChangedEvent(event) {
435+
const fileType = event.target.files[0]?.type;
436+
fileInputChanged(fileType);
437+
}
438+
window.fileInputChanged = fileInputChangedEvent;
439+
440+
function fileInputChanged(fileType) {
441+
const outputType = outputTypeElement.value;
442+
if (fileType === "image/png" && outputType === "image/png") {
443+
outputTypeElement.value = "image/jpeg";
444+
selectChanged({ target: outputTypeElement });
445+
} else if (fileType === "image/jpeg" && outputType === "image/jpeg") {
446+
outputTypeElement.value = "image/png";
447+
selectChanged({ target: outputTypeElement });
448+
}
449+
showActions();
450+
hideError();
451+
}
452+
338453
</script>
339454
</body>
340455
</html>

pkg/image_convert.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
/* eslint-disable */
33
export function convert_exposed(image_data: Uint8Array, input: string, output: string, options: EncoderInput): Uint8Array;
44
export class EncoderInput {
5-
private constructor();
65
free(): void;
6+
constructor(quality?: number | null, compression?: string | null, filter?: string | null);
77
}
88

99
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
1010

1111
export interface InitOutput {
1212
readonly memory: WebAssembly.Memory;
1313
readonly __wbg_encoderinput_free: (a: number, b: number) => void;
14+
readonly encoderinput_new: (a: number, b: number, c: number, d: number, e: number) => number;
1415
readonly convert_exposed: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number, number];
1516
readonly __wbindgen_exn_store: (a: number) => void;
1617
readonly __externref_table_alloc: () => number;

pkg/image_convert.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,21 @@ export class EncoderInput {
244244
const ptr = this.__destroy_into_raw();
245245
wasm.__wbg_encoderinput_free(ptr, 0);
246246
}
247+
/**
248+
* @param {number | null} [quality]
249+
* @param {string | null} [compression]
250+
* @param {string | null} [filter]
251+
*/
252+
constructor(quality, compression, filter) {
253+
var ptr0 = isLikeNone(compression) ? 0 : passStringToWasm0(compression, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
254+
var len0 = WASM_VECTOR_LEN;
255+
var ptr1 = isLikeNone(filter) ? 0 : passStringToWasm0(filter, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
256+
var len1 = WASM_VECTOR_LEN;
257+
const ret = wasm.encoderinput_new(isLikeNone(quality) ? 0xFFFFFF : quality, ptr0, len0, ptr1, len1);
258+
this.__wbg_ptr = ret >>> 0;
259+
EncoderInputFinalization.register(this, this.__wbg_ptr, this);
260+
return this;
261+
}
247262
}
248263

249264
const EXPECTED_RESPONSE_TYPES = new Set(['basic', 'cors', 'default']);

pkg/image_convert_bg.wasm

343 Bytes
Binary file not shown.

pkg/image_convert_bg.wasm.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/* eslint-disable */
33
export const memory: WebAssembly.Memory;
44
export const __wbg_encoderinput_free: (a: number, b: number) => void;
5+
export const encoderinput_new: (a: number, b: number, c: number, d: number, e: number) => number;
56
export const convert_exposed: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => [number, number, number, number];
67
export const __wbindgen_exn_store: (a: number) => void;
78
export const __externref_table_alloc: () => number;

src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ pub struct EncoderInput {
1717
filter: Option<String>,
1818
}
1919

20+
#[wasm_bindgen]
21+
impl EncoderInput {
22+
#[wasm_bindgen(constructor)]
23+
pub fn new(quality: Option<u8>, compression: Option<String>, filter: Option<String>) -> EncoderInput {
24+
EncoderInput { quality, compression, filter }
25+
}
26+
}
27+
2028
impl EncoderInput {
2129
fn to_options(&self, format: ImageFormat) -> EncoderOptions {
2230
match format {

0 commit comments

Comments
 (0)